MooFoo blogs Artem Shubovych' blog. urn:uuid:663e7fde-2b5b-5aaa-bf01-0efc364a31ca 2026-02-10T03:21:23Z Data compression urn:uuid:266875ca-863e-5383-b33b-722e2508a242 2025-12-01T00:00:00Z 2025-12-01T00:00:00Z Data compression Artem Shubovych

I have been curious about how data compression works for a very long time - back in the day there was an archiver race, with WinRar and KGB archiver being insanely good at it. Bear in mind, those were the days where you had to use 1.44MB 3.5" magnetic "floppy" disks to transfer data - that was the era before DVD and even CD disks. And what WinRar could offer was no joke - you could compress 14MB Doom 2 and split it into 5 tomes , write each of them to a separate disk and then unarchive them on another computer - archiver would prompt you to insert the next disk with the next tome when it is done decompressing the current one.

But I digress. I was curious how WinRar can do that and how the size of the data is actually reduced.

And recently I got back to this topic. What I found was actually quite interesting.

Back in the day I had an idea to transform the data like so: for each character, replace it with a short code followed by the number of times it is repeated in a row:

<code>AAAAABBB (8 characters)

  |
  v

A5B3 (4 characters - 50% compression!)
</code>

This is exactly what run-length encoding is doing. The problem with this solution was that even this very text does not contain a whole lot of repeated characters in a row, so it is quite inefficient:

<code>Hello world (11 characters)

     |
     v

H1e1l2o1 1w1o1r1l1d1 (20 characters - negative 100% compression)
</code>

The next idea I had was to represent each character's original binary code with a shorter one:

<code>Hello world

H (72 = 01001000 => 000000001)
e (101 = 01100101 => 00000010)
l (108 = 01101100 => 00000011) &#x3C;------\
l (108 = 01101100 => 00000011) &#x3C;-----/|
o (111 = 01101111 => 00000100) &#x3C;-\    |
  (32 = 00100000 => 00000101)    |    |
w (119 = 01110111 => 00000110)   |    |
o (111 = 01101111 => 00000100) &#x3C;-/    |
r (114 = 01110010 => 00000111)        |
l (108 = 01101100 => 00000011) &#x3C;------/
d (100 = 01100100 => 00001000)

Original:

Hello world
01001000 01100101 01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100

New:

00000001 00000010 00000011 00000011 00000100 00000101 00000110 00000100 00000111 00000011 00001000
</code>

On itself this does not present any compression, but what if characters were packed into half-bytes? The longest short code is only 4 (meaningful) bits, so we could get rid of most of zeros:

<code>Old:

0000'0001 0000'0010 0000'0011 0000'0011 0000'0100 0000'0101 0000'0110 0000'0100 0000'0111 0000'0011 0000'1000

(11 bytes)

New:

0001'0010 0011'0011 0100'0101 0110'0100 0111'0011 1000'0000

(6 bytes)
</code>

This is a reduction of about 50%! But this method does not preserve the mapping of characters to short codes. If we were to add this mapping, the message size would be actually much larger:

<code>01001000 00000001 01100101 00000010 01101100 00000011 01101111 00000100 00100000 00000101 01110111 00000110 01110010 00000111 01100100 00001000
H        code     e        code     l        code     o        code     &#x3C;space>  code     w        code     r        code     d        code
</code>

This is already 16 bytes. Then add the 6 bytes for the encoded message and you get 22 bytes - a -100% (negative 100%) compression again.

If the initial text was much, much longer, this could actually be an improvement, but here's the challenge: once the number of unique letters in the initial text is larger than 15 (the maximum number of variants that could be represented by 4 bits), the compression rate drops below zero - simply because we can not represent every character in less than a full byte anymore.

Literal decades of break and I learned about Huffman encoding . The idea is somewhat similar - represent each letter of the input text with a short(er) code. The algorithm looks like this: get all the unique letters of the input text, order them by the number of their occurrences in the text, in decreasing order:

<code>l => 3
o => 2
d => 1
r => 1
w => 1
" " => 1
e => 1
H => 1
</code>

Within this list, order the pairs with the same number of occurrences by the character code, in ascending order:

<code>l => 3
o => 2
" " => 1
H => 1
d => 1
e => 1
r => 1
w => 1
</code>

Imagine each of these entries as a node:

Then, take a pair of nodes with the smallest number of occurrences each and merge them into a new node with the number of occurrences as a sum of two original nodes:

Repeat this process until there is just one node left:

And again:

There are four candidates for the smallest amongst the (2) nodes: (o, 2) and three internal nodes; in this case the (o, 2) node will become the left branch (because the ordering of the characters - none of the internal nodes has the character assigned, but the (o, 2) node has it; its code is lexicographically larger than the empty character, assuming empty character has code of 0 ):

Note how the node (l, 3) has moved to the middle of the list, between (4) and (2) nodes - this is needed to preserve the ordering by the number of occurrences.

There are two more nodes (2) , join them:

Now the smallest two nodes are (l, 3) and (4) :

And lastly there are (7) and (4) nodes to merge:

Then, following the rule "left branch -> '0', right branch -> '1'" , mark each branches of this tree:

Lastly, by following the branches from the root node of this tree, gather the branch labels into the binary code for each of the leaf nodes:

<code>(l, 3, 0b01)  (o, 2, 0b11)  (" ", 1, 0b100)  (H, 1, 0b101)  (d, 1, 0b0010)  (e, 1, 0b0011)  (r, 1, 0b0000)  (w, 1, 0b0001)
</code>

This is called Huffman encoding or Huffman tree. Using these codes, the initial text Hello world is encoded as following:

<code>H   e    l  l  o      w    o  r    l  d
101 0011 01 01 11 100 0001 11 0000 01 0010

joining into bytes

10100110 10111100 00011100 00010010
</code>

This could be programmed in Ruby like so:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Hello world'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">uniq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)}}.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sort</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;=></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pq </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#D20F39;--shiki-dark:#E78284"> count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#D20F39;--shiki-dark:#E78284"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  pq </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#D20F39;--shiki-dark:#E78284"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sort!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;=></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">q </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [{</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#D20F39;--shiki-dark:#E78284"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">codes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  e </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">shift</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][:</span><span style="color:#D20F39;--shiki-dark:#E78284">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][:</span><span style="color:#D20F39;--shiki-dark:#E78284">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    next</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][:</span><span style="color:#D20F39;--shiki-dark:#E78284">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#D20F39;--shiki-dark:#E78284"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][:</span><span style="color:#D20F39;--shiki-dark:#E78284">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][:</span><span style="color:#D20F39;--shiki-dark:#E78284">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#D20F39;--shiki-dark:#E78284"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][:</span><span style="color:#D20F39;--shiki-dark:#E78284">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

or in C++:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;string></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;map></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;queue></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;iostream></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    char</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CodeNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello world"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cmpNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [](</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> !=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">priority_queue</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> decltype</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cmpNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cmpNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Node{.c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .count </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">swap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Node{ .c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .count </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">queue</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CodeNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeNode{ .node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">front</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeNode{ .node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "0"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeNode{ .node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "'"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "'"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ": "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

If the Huffman table is known, the source could be decoded by traversing from the root: if the next bit in the input sequence is 0 - traverse the left child of the current node, if the next bit is 1 - traverse the right child of the current node; if the leaf node is reached - emit a corresponding character:

In Ruby:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">encoded </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]}.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tree </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> encoded</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  encoded</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#179299;--shiki-dark:#81C8BE"> not</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      res </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  res</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Or in C++:

<code><span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;string></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;map></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;queue></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;iostream></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    char</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CodeNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Node</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> buildHuffmanTree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string_view</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cmpNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [](</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> !=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">priority_queue</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Node </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Node </span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> decltype</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cmpNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      cmpNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Node{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        .c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .count </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">swap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Node{.c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                     .count </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                     .left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                     .right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> encode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string_view</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">queue</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CodeNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeNode{.node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">front</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeNode{.node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "0"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeNode{.node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ch </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string_view</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ch </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      res </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello world"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> buildHuffmanTree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> encoded </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> encode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decoded </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> encoded</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Input: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Encoded: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> encoded </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Decoded: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decoded </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

To construct a Huffman tree from encodings table (given the encodings are sorted in the descending order of their frequency), a very simple algorithm is used - traverse the tree by the bits of the character encoding and if there is no node matched, add to the last seen node - a left child if a bit is 0 or a right child if a bit is 1 .

As an example from above, consider the following encodings table (sorted already):

<code>l => 0b01; o => 0b11; " " => 0b100; H => 0b101; d => 0b0010; e => 0b0011; r => 0b0000; w => 0b0001
</code>

Iterate over the encodings one by one, starting with l => 0b01 :

encoding: (l, 0b01) tree is empty (has only root node), the current node is root:

first bit: 0 , add a new left child to the current node and make this new child node the current one:

next bit: 1 , add a new right child to the previously added node and make it the new current node:

since this is the last bit, add the value to the current node:

Next encoding, o => 0b11 , reset the current node to the root:

first bit: 1 , add a new right child node to the current node and make it the new current:

next bit: 1 , add a new right child node and make it current:

since this is the last bit, add the value to the current node:

Next encoding, " " => 0b100 , reset the current node (*) to the root:

first bit: 1 , no changes to the tree, since the right child of the current node exists:

next bit: 0 , add a new left child to the current node and make it the new current (*):

next bit: 0 , add a new left child to the current node and make it the new current (*):

since this is the last bit, add a value to the current node:

Next encoding is H => 0b101 , reset the current node (*) to root:

first bit is: 1 , no changes to the tree since the node exists, just make it current (*):

next bit is: 0 , no changes to the tree since the node exists, just make it current (*):

next bit is: 1 , add a right child node and make it current (*):

since this was the last bit, add a value to the current node:

And without going step-by-step, for all the remaining encodings: encoding: d => 0b0010 :

encoding: e => 0b0011 :

encoding: r => 0b0000 :

encoding: w => 0b0001 :

If the initial message ( Hello world ) is encoded with this algorithm (to four bytes: 0xA6 0xBC 0x1C 0x12 ), in order to properly decode it, the tree or the code table has to be given alongside with the encoded message:

<code>message: 'Hello world' (11 bytes)
encoded: 0xA6 0xBC 0x1C 0x12 (4 bytes)
table:   {"l"=>"01", "o"=>"11", " "=>"100", "H"=>"101", "r"=>"0000", "w"=>"0001", "d"=>"0010", "e"=>"0011"} (8 keys + 8 values = 16 bytes)
compression = 11 bytes -> 20 bytes = negative 100%
</code>

This is not entirely a compression algorithm, though. Algorithms such as ZIP (DEFLATE) and JPEG (although slightly different in details, the general approach still applicable) go further to compress the table itself. To understand how they work, one needs to understand the tricks behind them.

Canonical Huffman codes

There is one issue with just general Huffman encoding: there are multiple ways to build a different tree for the same input. Refer to the early stage of encoding from above:

<code>(l, 3)  (2)   (o, 2)      (2)               (2)
      /     \           /     \           /     \
 (" ", 1) (H, 1)    (d, 1)  (e, 1)     (r, 1) (w, 1)
</code>

Here's the non-deterministic part: which pair of nodes to merge next? Depending on the choice, the code for each character would be different (although the code length would remain the same).

That's where canonical Huffman codes come into play: this simple algorithm unifies the logic, transforming any valid Huffman tree for a given input into the same tree (so the codes remain the same).

To obtain canonical codes from any valid Huffman tree for a given input, the codes are transformed following two simple rules:

  1. sort the codes by code length (ascending) and then by character (also ascending)
  2. starting with current_code = 0 and current_length = 0 , iterate over each code length (assume iterator is length_i ):
  3. if the length is greater than current_length , left shift current_code by the difference length_i - current_length
  4. increment current_code , filling the unused left-most bits with zeroes
  5. update current_length to length_i

In the example above, the codes are:

<code>l:   01
o:   11
" ": 100
H:   101
r:   0000
w:   0001
d:   0010
e:   0011
</code>

The lengths of those codes are:

<code>l:   2 (Huffman code: '01', length of '01' = 2)
o:   2 (Huffman code: '11', length of '11' = 2)
" ": 3 (Huffman code: '100', length of '100' = 3)
H:   3 (Huffman code: '101', length of '101' = 3)
r:   4 (Huffman code: '0000', length of '0000' = 4)
w:   4 (Huffman code: '0001', length of '0001' = 4)
d:   4 (Huffman code: '0010', length of '0010' = 4)
e:   4 (Huffman code: '0011', length of '0011' = 4)
</code>

Making these codes canonical requires sorting by Huffman code's length first and then by character (I have left old codes in braces for reference):

<code>l:   2 (old code: 01, its length = 2)
o:   2 (old code: 11, its length = 2)
" ": 3 (old code: 100, its length = 3)
H:   3 (old code: 101, its length = 3)
d:   4 (old code: 0010, its length = 4)
e:   4 (old code: 0011, its length = 4)
r:   4 (old code: 0000, its length = 4)
w:   4 (old code: 0001, its length = 4)
</code>

Then, re-assign codes, starting with 0 and padding to the length of old code:

<code>l:   00 (old code length = 2, next code = 00 + 1 = 01)
o:   01 (old code length = 2, next code = 01 + 1 = 10)
" ": 100 (old code length = 3; but previous entry ('o' = 01) has length 2, so shift left by 1 bit ('10' &#x3C;&#x3C; 1 == '100'); next code = 100 + 1 = 101)
H:   101 (old code length = 3; next code = 101 + 1 = 110)
d:   1100 (old code length = 4; but previous entry ('H' = 101) has length 3, so shift left by 1 bit ('110' &#x3C;&#x3C; 1 == '1100'); next code = 1100 + 1 = 1101)
e:   1101 (old code length = 4; next code = 1101 + 1 = 1110)
r:   1110 (old code length = 4; next code = 1110 + 1 = 1111)
w:   1111 (old code length = 4)
</code>

Interestingly, this code did not use the previous codes themselves. This implies the codes could be calculated automatically if only the lengths of the codes are given.

For the example above, the encoding table is:

<code>l:   00
o:   01
" ": 100
H:   101
d:   1100
e:   1101
r:   1110
w:   1111
</code>

Encoded message with this table looks like this:

<code>message:

Hello world

encoded:

101 1101 00 00 01 100 1111 01 1110 00 1100

joined:

10111010000011001111011110001100
</code>

In Ruby:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> build_canonical_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    codes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sort_by</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    canonical_codes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    curr_code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    prev_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> old_code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        curr_code </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">old_code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        canonical_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> curr_code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rjust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">old_code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        curr_code </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        prev_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> old_code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    canonical_codes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

In C++:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">vector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">pair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sorted_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">codes</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> codes</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sort</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sorted_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sorted_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [](</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> !=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> canonical_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> curr_code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sorted_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    curr_code </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    canonical_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bitset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">curr_code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">substr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    curr_code</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    prev_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

ZIP, DEFLATE

DEFLATE algorithm compresses the list of codes lengths using a constant table, defined by the standard (or algorithm description, if you will).

The constant table is defined in the archiver code itself, so it remains the same for all archives and does not need to be a part of archive itself.

The archive, on the other hand, stores a list of 256 values, each representing the length of the code of the corresponding character.

For example, archive may store a list like this:

<code>0, 0, 2, 2, 4, 0, 0, 0, 0, ... (total 256 elements, all the rest are zeros)
</code>

But this is highly inefficient, so this list is also comressed using Huffman encoding. The difference is that this list is first compressed using run-length encoding (from the very top of this blog) and the result is compressed using the pre-defined Huffman table.

Step-by-step this looks like this: first, the original content is compressed. This produces a Huffman table. Assume this table of canonical Huffman codes for input Hello world :

<code>l  : "00"
o  : "01"
" ": "100"
H  : "101"
d  : "1100"
e  : "1101"
r  : "1110"
w  : "1111"
</code>

As described above, for canonical Huffman codes, storing only codes' lengths is enough to reconstruct the codes :

<code>"00"   : 2
"01"   : 2
"100"  : 3
"101"  : 3
"1100" : 4
"1101" : 4
"1110" : 4
"1111" : 4
</code>

So the table of codes' lengths looks like this:

<code>1: 0 (codes of length 1: none)
2: 2 (codes of length 2: two codes)
3: 2 (codes of length 3: two codes)
4: 4 (codes of length 4: four codes)
</code>

This table looks very much like an indexed array (1-based, though - indexes start at 1 instead of 0 like in C), so it could be represented as an array.

Given this data, at any point Huffman codes could be re-created:

<code>code = 0

// lengths: [0, 2, 2, 4]

length_i = 1, codes_length_i = 0;
  no codes of length 1 => skip

length_i = 2, codes_length_i = 2;
  code (0) &#x3C;&#x3C; 1 => code = 00;
  create &#x3C;codes_length_i (2)> codes:
    emit code (00), code += 1 (code = 01);
    emit code (01), code += 1 (code = 10);

length_i = 3, codes_length_i = 2;
  code (10) &#x3C;&#x3C; 1 => code = 100;
  create &#x3C;codes_length_i (2)> codes:
    emit code (100), code += 1 (code = 101)
    emit code (101), code += 1 (code = 110);

length_i = 4, codes_length_i = 4;
  code (110) &#x3C;&#x3C; 1 => code = 1100;
  create &#x3C;codes_length_i (4)> codes:
    emit code (1100), code += 1 (code = 1101);
    emit code (1101), code += 1 (code = 1110);
    emit code (1110), code += 1 (code = 1111);
    emit code (1111), code += 1 (code = 10000);
</code>

So for the list of codes lengths [0, 2, 2, 4] the re-created codes will be

<code>00
01
100
101
1100
1101
1110
1111
</code>

In Ruby:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> recreate_canonical_huffman_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">codes_of_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  codes_of_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_with_index</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    code </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rjust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      code </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  res</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

For the second phase, the original symbols have to be correlated with these codes somehow. DEFLATE does not store the symbols or their corresponding encodings at any point - instead it uses smart algorithm to encode the encodings (so meta!) for all possible symbols.

Referring back to the compressed content's table of codes:

<code>l  : "00" (code length: 2)
o  : "01" (code length: 2)
" ": "100" (code length: 3)
H  : "101" (code length: 3)
d  : "1100" (code length: 4)
e  : "1101" (code length: 4)
r  : "1110" (code length: 4)
w  : "1111" (code length: 4)
</code>

In a similar manner to codes lengths' table, a table of all possible 256 byte values (ASCII table, effectively) is created and the corresponding byte's code length is written to this table:

<code>0x00: 0
0x01: 0
0x02: 0
...
0x20 (" "): 3
...
0x48 (H)  : 3
...
0x64 (d)  : 4
0x65 (e)  : 4
...
0x6c (l)  : 2
...
0x6f (o)  : 2
...
0x72 (r)  : 4
...
0x77 (w)  : 4
...
</code>

Instead of hexadecimal values, here's decimal representation:

<code>32  (" ") : 3
72  (H)   : 3
100 (d)   : 4
101 (e)   : 4
108 (l)   : 2
111 (o)   : 2
114 (r)   : 4
119 (w)   : 4
</code>

This list could be written as follows:

<code>index: [0, 1, 2, 3, 4, ..., 31, 32, 33, 34, 35, ..., 71, 72, 73, ..., 99, 100, 101, 102, ..., 108, ..., 111, 112, 113, 114, ..., 119, ..., 255 ]
value: [0, 0, 0, 0, 0, ..., 0,  3,  0,  0,  0,  ...,  0,  3,  0, ...,  0,   4,   4,   0, ...,   2, ...,   2,   0,   0,   4, ...,   4, ..., 0 ]
</code>

This list contains a lot of duplications and a lot of zeroes. It is then compressed using the run-length algorithm (from the very top of this blog), which now makes sense:

<code>(0, 32), (3, 1), (0, 39), (3, 1), (0, 27), (4, 1), (4, 1), (0, 6), (2, 1), (0, 2), (2, 1), (0, 2), (4, 1), (0, 4), (4, 1), (0, 136)
</code>

But DEFLATE does it smarter - it uses pre-defined table of symbols, again:

  • for zero value, use zero itself
  • for values 1..15, use the value itself as a code
  • to repeat previous value 3..6 times, use code 16 and 3 extra bits to represent how many repetitions ( 0 - repeat previous value 3 times, 1 - repeat previous value 4 times, 10 - repeat previous value 5 times, 11 - repeat previous value 6 times)
  • to repeat value 0 3..10 times, use code 17 and extra bits
  • to repeat value 0 11..138 times, use code 18 and extra bits

And then DEFLATE compresses the table of codes' lenghts with Huffman encoding. Since there is a very limited number of characters to encode ( 1..15 , 16 , 17 , 18 - 19 values total), the maximum code length, even if all of these values were used, would be about 4 bits. The values 16 , 17 and 18 will always be followed by a pre-defined number of bits (extra bits describing a parameter), so when decoding, if the value decoded is one of those three ( 16 , 17 or 18 ), the following pre-defined number of bits are interpreted differently.

Look at this process step-by-step. First, the code lenghts array is replaced with the codes from above using run-length algorithm:

Repeated zeros are represented by following this simple table:

  • single zero: 0
  • two zeros: 0, 0 (two zero bytes)
  • 3..10 zeros: 17 followed by
    • 0 for 3 zeros
    • 1 for 4 zeros
    • 2 for 5 zeros
    • etc.
    • 7 for 10 zeros
  • 11..138 zeros: 18 followed by
    • 0 for 11 zeros
    • 1 for 12 zeros
    • etc.
    • 127 for 138 zeros

These extra bits are not encoded using Huffman codes. The rest of the codes (raw values 0..15 , 16 , 17 , 18 ) are encoded according to their frequencies.

<code>(0, 32)  -> 18 (repeat '0' 32 times), followed by extra bits representing 32 repetition: 32 - 11 = 21 (0b00010101)
(3, 1)   -> 3
(0, 39)  -> 18 (repeat '0' 39 times), followed by extra bits representing 39 repetitions: 39 - 11 = 28 (0b00011100)
(3, 1)   -> 3
(0, 27)  -> 18 (repeat '0' 27 times), followed by extra bits representing 27 repetitions: 27 - 11 = 16 (0b00010000)
(4, 1)   -> 4
(4, 1)   -> 4
(0, 6)   -> 17 (repeat '0' 6 times), followed by extra bits representing 6 repetitions: 6 - 3 = 3 (0b00000011)
(2, 1)   -> 2
(0, 2)   -> [0, 0]
(2, 1)   -> 2
(0, 2)   -> [0, 0]
(4, 1)   -> 4
(0, 4)   -> 17 (repeat '0' 4 times), followed by extra bits representing 4 repetitions: 4 - 3 = 1 (0b00000001)
(4, 1)   -> 4
(0, 136) -> 18 (repeat '0' 136 times), followed by extra bits representing 136 repetitions: 136 - 11 = 125 (0b01111101)
</code>

After this, the codes lengths list becomes:

<code>18, 21 (0b00010101), 3, 18, 28 (0b00011100), 3, 18, 16 (0b00010000), 4, 4, 17, 3 (0b00000011), 2, 0, 0, 2, 0, 0, 4, 17, 1 (0b00000001), 4, 18, 125 (0b01111101)
</code>

In Ruby:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> running_codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    codes_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">..</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">chr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        len </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        i </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                    # code 18, repeat '0' 11..138 times</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">138</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    result </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                elsif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                    # code 17, repeat '0' 3..10 times</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    result </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">17</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        elsif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                # code 16, repeat previous value 3..6 times</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                result </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

In C++:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CodeLengthNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    size_t</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CodeLengthNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 256</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> canonical_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 256</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> canonical_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        run_length</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    i </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // code 18, repeat '0' 11..138 times</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">138</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeLengthNode{ .length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // code 17, repeat '0' 3..10 times</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeLengthNode{ .length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 17</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeLengthNode{ .length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeLengthNode{ .length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        run_length</span><span style="color:#179299;--shiki-dark:#81C8BE">--</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeLengthNode{ .length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> run_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CodeLengthNode{ .length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        run_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

To compress this list, ignore the extra bits and count values 0..18 only:

<code>18, 21, 3, 18, 28, 3, 18, 16, 4, 4, 17, 3, 2, 0, 0, 2, 0, 0, 4, 17, 1, 4, 18, 125

without extra bit values:

18, 3, 18, 3, 18, 16, 4, 4, 17, 3, 2, 0, 0, 2, 0, 0, 4, 17, 1, 4, 18

counts:

18 : 4
3  : 3
16 : 1
4  : 4
17 : 2
2  : 2
0  : 4
1  : 1
</code>

Next, order these mappings by count, followed by the number itself (key of this dictionary / hashmap):

<code>0  : 4
4  : 4
18 : 4
3  : 3
2  : 2
17 : 2
1  : 1
16 : 1
</code>

Then, create Huffman tree for these counts:

step 1:

step 2:

step 3:

step 4:

Following the rule "left branch => 0, right branch => 1", traverse the tree and assign codes to each leaf node:

This yields:

<code>(0, 4, 00) (4, 4, 01) (18, 4, 100) (3, 3, 101) (2, 2, 1100) (17, 2, 1101) (1, 1, 1110) (16, 1, 1111)
</code>

or

<code>0 (4 occurrences)  : 00
4 (4 occurrences)  : 01
18 (4 occurrences) : 100
3 (3 occurrences)  : 101
2 (2 occurrences)  : 1100
17 (2 occurrences) : 1101
1 (1 occurrences)  : 1110
16 (1 occurrences) : 1111
</code>

Then, assign the canonical Huffman codes:

<code>step 1: sort codes by lengths and code itself:

0  : 00    (code length: 2)
4  : 01    (code length: 2)
18 : 100   (code length: 3)
3  : 101   (code length: 3)
2  : 1100  (code length: 4)
17 : 1101  (code length: 4)
1  : 1110  (code length: 4)
16 : 1111  (code length: 4)

becomes

0  : 00    (code length: 2)
4  : 01    (code length: 2)
3  : 101   (code length: 3)
18 : 100   (code length: 3)
1  : 1110  (code length: 4)
2  : 1100  (code length: 4)
16 : 1111  (code length: 4)
17 : 1101  (code length: 4)

step 2: assign incrementing and shifting code:

code = 0, previous_length = 0

0  : 00    (code length: 2), code = 00, next code = 01
4  : 01    (code length: 2), code = 01, next code = 10
3  : 101   (code length: 3), length > previus_length => shift code, code = 100, next code = 101
18 : 100   (code length: 3), code = 101, next code = 110
1  : 1110  (code length: 4), length > previous_length => shift code, code = 1100, next code = 1101
2  : 1100  (code length: 4), code = 1101, next code = 1110
16 : 1111  (code length: 4), code = 1110, next code = 1111
17 : 1101  (code length: 4), code = 1111
</code>

Going back to what the initial codes' lengths list was (the thing being encoded):

<code>18, 21 (0b00010101), 3, 18, 28 (0b00011100), 3, 18, 16 (0b00010000), 4, 4, 17, 3 (0b00000011), 2, 0, 0, 2, 0, 0, 4, 17, 1 (0b00000001), 4, 18, 125 (0b01111101)
</code>

Now encoded with this new Huffman encoding:

<code>100, 00010101, 101, 100, 00011100, 101, 100, 1111, 00010000, 01, 01, 1101, 101, 00000011, 1100, 00, 00, 1100, 00, 00, 01, 1101, 1110, 00000001, 01, 100, 01111101

joined:

1000001010110110000011100101100111100010000010111011010000001111000000110000000111011110000000010110001111101
</code>

And the tree for this encoding could be just a list of 19 elements (one for each code used in this code lengths encoding) of codes lengths (for the encoded code lengths list):

<code>0  : 00    (code length: 2)
4  : 01    (code length: 2)
3  : 101   (code length: 3)
18 : 100   (code length: 3)
1  : 1110  (code length: 4)
2  : 1100  (code length: 4)
16 : 1111  (code length: 4)
17 : 1101  (code length: 4)

simplified:

0  : 2
1  : 4
2  : 4
3  : 3
4  : 2
16 : 4
17 : 4
18 : 3

becomes

index: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 ]
value: [ 2, 4, 4, 3, 2, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  4,  4,  3 ]

or just

2, 4, 4, 3, 2, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  4,  4,  3
</code>

Note one interesting observation: since there is a very limited number of symbols used to encode code lengths, the maximum code for them is 7 , which is 3 bits long. This means the new encodings for code lengths table could be packed into 3 bit chunks, further reducing the size of this tree:

<code>codes lengths (for codes lengths, so meta!):

2, 4, 4, 3, 2, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  4,  4,  3

encoded into binary:

010, 100, 100, 011, 010, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 100, 100, 011

joined:

010100100011010000000000000000000000000000000000100100011
</code>

Now, build the header for the archive, consisting of code lengths encoded with DEFLATE:

<code>code lengths tree:

010100100011010000000000000000000000000000000000100100011

code lengths for each character, encoded:

1000001010110110000011100101100111100010000010111011010000001111000000110000000111011110000000010110001111101

in bytes:

01010010 01110100 00000000 00000000 00000000 00000000 10010001 11000001 01001011 00000111 00101100 11110001 00000101 11011010 00000111 10000001 10000000 11101111 00000000 10110001 111101

in hex:

0x52 0x74 0x00 0x00 0x00 0x00 0x91 0xC1 0x4B 0x07 0x2C 0xF1 0x05 0xDA 0x07 0x81 0x80 0xEF 0x00 0xB1 0x3D
</code>

And build the content of the archive, which is just the encoded message (from a while ago):

<code>encoded message:

10111010000011001111011110001100

in bytes:

10111010 00001100 11110111 10001100

in hex:

0xBA 0x0C 0xF7 0x8C
</code>

Joining header and the body:

<code>0x52 0x74 0x00 0x00 0x00 0x00 0x91 0xC1 0x4B 0x07 0x2C 0xF1 0x05 0xDA 0x07 0x81 0x80 0xEF 0x00 0xB1 0x3D 0xBA 0x0C 0xF7 0x8C
</code>

Funny enough, the length of this archive is much longer than the original message itself - 25 bytes vs original 11 - more than negative 100% increase in size. But the important part is that this is due to the fact that the message is short and most symbols only occur once. On a longer text the compression is actually good: a typical AI response compression:

<code>Source length: 3994
Encoded length: 2632
> encoded length: 2573
> header length: 59
>> header1 length: 8
>> header2 length: 51
Compression rate: 51%
</code>

Decoding works the same three-step way, just in the reverse:

  1. decode canonical Huffman tree for codes' lengths
  2. decode codes' lengths and build the canonical Huffman tree again
  3. decode the message using that tree

The only tricky part there is decoding the codes' lengths, since it involves re-building the symbols + extra bits for repeated values.

Decoding codes' lengths:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_code_lengths_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rjust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)}.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    code_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">..</span><span style="color:#FE640B;--shiki-dark:#EF9F76">18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        start_bit </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        three_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start_bit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> three_bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> length</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    code_lengths</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Then the canonical Huffman codes are reconstructed for decoding next stage of codes' lengths:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> recreate_huffman_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    symbols_with_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_with_index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sort_by</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    prev_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    code </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    symbols_with_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        code </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rjust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        code </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        prev_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

This is then used to decode running lengths (compressed lengths):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_compressed_code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> codes_lengths_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    tree_inv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_lengths_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_with_index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_h</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    compressed_code_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    decoded_count </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decoded_count </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 256</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        buf </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree_inv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">key?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            symbol </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree_inv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> symbol</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                compressed_code_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                decoded_count </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># code 16 repeats 3-6 repetitions</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 17</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                compressed_code_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">17</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                decoded_count </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># code 17 repeats 3-10 repetitions</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                compressed_code_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                decoded_count </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># code 18 repeats 11-138 repetitions</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                compressed_code_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> symbol</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                decoded_count </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # any other code adds 1 instance of itself</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    compressed_code_lengths</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Which is then used to reconstruct all codes' lengths for all symbols:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_running_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">compressed_code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    compressed_code_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_a?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">Array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extras </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extras</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">last</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 17</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extras</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extras</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

These last two methods are there just to showcase the same process as encoding, but in reverse. Practically speaking, it does not make sense to build the intermediate running lengths encoding (with codes 16 , 17 and 18 ) and the actual list could be built in-place:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> codes_lengths_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rjust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)}.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    tree_inv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_lengths_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_with_index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_h</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 256</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        buf </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree_inv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">key?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            symbol </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree_inv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> symbol</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">last</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 17</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            when</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                extra_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit_pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                bit_pos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extra_bits</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                repeats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> symbol</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

This list is then used to create the ultimate canonical Huffman codes for the message itself (the "body" of the archive), by calling recreate_huffman_codes :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">header1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> header2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    code_lengths_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_code_lengths_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">header1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    tree </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> recreate_huffman_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code_lengths_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    codes_lengths </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">header2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    codes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> recreate_huffman_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    decode_body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Decoding the body with this tree is simple:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_with_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    tree_inv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_with_index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_h</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_char</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        buf </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bit</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree_inv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">key?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree_inv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rjust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)}.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bytes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_with_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_lengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pack</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'C*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">force_encoding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'UTF-8'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Note how these methods use string.bytes instead of string.chars - this is to make the algorithm work with UTF-8 characters and not only ASCII.

For binary data it can be hit or miss. For example, a PNG is already a compressed binary data, so DEFLATE does not prove too useful:

<code>Raw data (PNG file): 2356 bytes
Encoded: 2397 bytes
Compression ratio: -1%
</code>

For a larger uncompressed data (so potentially more of the same characters being used more frequently), like a TTF font:

<code>Raw data (TTF font): 7316 bytes
Encoded: 5161 bytes
Compression ratio: 29%
</code>

JPEG, DHT

Define Huffman Table uses a much simpler approach - it stores the list of codes lengths using an index-as-value approach - a list of 16 values effectively translated as "element at index 'i' tells how many codes of length 'i' are there in the table" . This list is followed by the list of raw characters used in the message.

For example, an array like this

<code>[0, 0, 2, 2, 4, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0]
</code>

is expanded like so:

<code>index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
value: [0, 0, 2, 2, 4, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0]

codes of length 0: 0
codes of length 1: 0
codes of length 2: 2
codes of length 3: 2
codes of length 4: 4
codes of length 5: 0
codes of length 6: 0
codes of length 7: 0
codes of length 8: 0
codes of length 9: 0
codes of length 10: 0
codes of length 11: 0
codes of length 12: 0
codes of length 13: 0
codes of length 14: 0
codes of length 15: 0
</code>

For the Hello world message, the archive header, comprising of codes' lengths and the alphabet, would look as following:

<code>canonical Huffman codes:

l:   00   (length: 2)
o:   01   (length: 2)
" ": 100  (length: 3)
H:   101  (length: 3)
d:   1100 (length: 4)
e:   1101 (length: 4)
r:   1110 (length: 4)
w:   1111 (length: 4)

number of codes per length:

[ 0, 0, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]

alphabet (in order same order as canonical Huffman codes table):

[ l, o, " ", H, d, e, r, w ]
</code>

Followed by the encoded message, the entire archive would look like this:

<code>codes per length:

[ 0, 0, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]

in bytes:

0x00 0x00 0x02 0x02 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

alphabet:

[ l, o, " ", H, d, e, r, w ]

in bytes:

0x6C 0x6F 0x20 0x48 0x64 0x65 0x72 0x77

encoded message:

10111010000011001111011110001100

in bytes:

0xBA 0x0C 0xF7 0x8C

combined:

0x00 0x00 0x02 0x02 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x6C 0x6F 0x20 0x48 0x64 0x65 0x72 0x77 0xBA 0x0C 0xF7 0x8C
</code>

The total length is 28 , almost triple the original length!

Implementing this in Ruby:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># using the three helpers from the previous implementations - build_tree, build_table, build_canonical_table</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> build_canonical_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  build_canonical_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">build_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">build_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> encode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  codes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> build_canonical_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  grouped_codes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">group_by</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  codes_count_by_length </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grouped_codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transform_values</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  header1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">..</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes_count_by_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  header2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">keys</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">byte</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">byte</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_slice</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">slice</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> slice</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ljust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    header1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> header1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    header2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> header2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Then, the final message would be comprised of joining those parts together:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> encode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Hello world'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">header1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">header2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pack</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'C*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">force_encoding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'UTF-8'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span></span></code>

As I said before, for a simple message such as Hello world the archive is 27 bytes long, which is longer than the original data itself. But for something longer, like the AI chatbot response from before it is actually a bit better:

<code>Original message: 3994
Encoded message: 2598
> header1: 15
> header2: 90
> body: 2573
Compression ratio: 49%
</code>

Decoding this is much simpler than DEFLATE: all there is to do is to reconstruct canonical Huffman codes from the number of codes by length (16-element-array)

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># using `recreate_huffman_codes` helper from before</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># decode_with_table is slightly different from decode_with_tree</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_with_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_char</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        buf </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bit</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">key?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            res </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  bytes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bytes</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  counts_encoded </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  counts </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counts_encoded</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each_with_index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatten</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  codes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> recreate_huffman_codes count</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  symbols </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  table </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">zip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">symbols</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_h</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body_encoded </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> codes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ..]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body_bits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body_encoded</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rjust</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body_decoded </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> decode_with_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body_bits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body_decoded</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pack</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'C*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">force_encoding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'UTF-8'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

By the way, all the code in this blog is available in a separate repo .

This algorithm works much worse with binary data, however:

<code>Raw data (PNG file): 2356 bytes
Encoded: 2605 bytes
Compression ratio: -2%
</code>

On a larger uncompressed binary data (same TTF font as before):

<code>Raw data (TTF font): 7316 bytes
Encoded: 5336 bytes
Compression ratio: 27%
</code>
Clean before running a Spring Boot application in IntelliJ Idea urn:uuid:ba70156f-c852-5f38-947a-03ec087fe22f 2025-07-12T00:00:00Z 2025-07-12T00:00:00Z Clean before running a Spring Boot application in IntelliJ Idea Artem Shubovych

My teammate has faced an issue when running our SpringBoot application in IntelliJ Idea: there were certain Gradle artifacts cached between switching the branches, which prevented the application from running. The issue is easily solved by running clean Gradle task. But my teammate was running it using IntelliJ's UI. And by default, it does not do a clean build before running - just the normal build, if the files have changed.

The solution was a bit of UI trickery.

In the run menu, edit the run configuration (from the meatball menu):

From the run configuration window, click the "Modify options" link:

In the "Before launch" section of a very long drop-down menu, click the "Add before launch task":

From the "Add task" pop-up menu select "Run Gradle task":

In the Gradle tak window fill out the "Gradle project" and "Tasks" fields (they both have auto-complete):

Bear in mind: this advice might become obsolete as IntelliJ team changes their new UI.

Modal text editors urn:uuid:f7d1b30a-bc53-5271-8c0a-3344fd0bd24d 2025-03-27T00:00:00Z 2025-03-27T00:00:00Z Modal text editors Artem Shubovych

I was using vim on-and-off since my pal showed me Linux on my first ever computer, back in circa 2005. I then learned emacs back in 2015 and used it for remote development (over SSH). That was the first time I used a bunch of plugins to improve my developer experience. Then, circa 2022, I heard about an interesting take on vim ideology - Kakoune . I liked how it allowed user to see what he is about to operate on before actually performing an action. I did not end up using it often, but I liked the idea. Then at the end of 2024, I heard about Helix - another take on Vim ideology (or more like Kakoune at that point). At some random morning, scrolling the suggested videos on YouTube, I stumbled upon a semi-interesting (at the time) video about Vim productivity tips . Creator showed an interesting plugin, flash, which allowed him to quickly jump between any two points on the screen - much faster and easier than what I usually would do in Vim (relative line numbers and motions). I really liked the idea, to a point where I was on the edge of giving it a try. Since we have a few people in our team using NeoVim or Vim plugin for VS Code or IntelliJ Idea, I thought about using each of them for a while for work and comparing the experience.

IntelliJ Idea, baseline

For a number of years, the way I develop in IntelliJ is quite keyboard-centric - I disable tabs and use Shift-Shift menu and its tabs to navigate the project and perform actions.

Quick Actions menu in IntelliJ Idea

The quick action menu has 6 tabs:

  • Classes
  • Files
  • Symbols
  • Actions
  • Text
  • All (combined of the above)

For the most part I only use Classes, Files and Actions tabs via a keyboard shortcut. From the Actions tab I rarely use more than "rename", "extract variable/method" or "copy path/reference".

The only other two features of the IDE I actually use are the file tree (so that I can see the structure of the project - it comes handy for Java packages organization, for example) which I configure to automatically focus the file currently opened in the editor and the terminal, which I use for pretty much everything else (including Git interactions and running / building project).

Actually, IntelliJ Idea gives you the statistics of features you use in the Help -> My Productivity menu.

My feature usage in IntelliJ Idea

In my case it looks like this (ordered by the usage frequency, descending - from most used to least):

  • Recent files
  • Go to declaration
  • Code completion
  • Syntax-aware selection ( Cmd + w )
  • Find in files
  • Context actions (suggestions like "remove unused", "replace with X", "import Y", etc.)
  • Find (in current file)
  • Toggle comment
  • Go to file
  • Go to class
  • Rename
  • Find and replace (in current file)
  • Generate code (constructors, getters and setters)
  • Go to implementation
  • Introduce variable
  • Change case (camel case)
  • Implement methods

Some of these (implement methods, introduce variable, generate code) might be hard to achieve in either of editors, so they are not requirements, but rather nice to haves.

So this would be my measure of success in other editors (in terms of comfort) - on top of movement in a document, I would like to compare the editors in terms of moving in the project (files, symbols / classes and references) and quick actions.

NeoVim

Neovim

I thought about trying NeoVim since it was the hype at the time. I was dumbfolded by the fact it did not even come with the default config file to work with (in a stumbling contrast to Helix, which has :config-open and :config-reload commands built in). Yet I kept going, spending days perfecting my config. I switched my terminal emulator from Warp to Ghostty (so that I can see images right inside my terminal, improving file manager experience), installed a good dozen of plugins and messed with color schemes.

My full neovim config is actually public .

After almost a week, my NeoVim plugin setup looked like this:

These three plugins alone allowed me to already be quite a bit productive compared to vanilla Vim experience. But it was not a complete setup:

A rather large set of plugins is required for autocomplete to work:

Those plugins make up for almost a complete setup.

But I wanted to further improve the Vim experience somewhat so motions become easier (like in the video from the top of the post):

  • nvim-treesitter-textobjects (?) - for moving between text blocks (paragraphs, function / class scopes, parameters, etc.)
  • nvim-surround - for operations on surrounding characters (braces, brackets, quotes, ticks, etc.)
  • flash - the fast movements
  • vim-visual-multi - true multi-cursor editing (unlike visual block mode, which would require macros for the best experience)

And there are a few quality-of-life improvements:

The config I have at the moment allows the following:

  • file tree
    • &#x3C;leader>n toggles NeoTree
    • when NeoVim opens, NeoTree opens too later I decided against this, since sometimes I want to just edit a single file without a care for the directory containing it
    • NeoTree follows the currently open file
    • NeoTree shows hidden files (including dot files and directories, like .github , which are hidden by default)
    • when NeoTree is the last open buffer, NeoVim will quit
  • movements
    • s performs a Flash search (with literal references to different points in text)
    • S-s performs a treesitter Flash search
  • terminal
    • trying to utilize zellij instead of built-in NeoVim terminal, following the "one tool for its purpose" principle
    • &#x3C;leader>t toggles a terminal
    • C-\ C-n switches terminal to Normal mode, but I also remapped it to &#x3C;Esc>&#x3C;Esc>
    • i switches terminal to Insert mode
  • navigation
    • C-left / C-right goes through the jumplist (similarly to back/forward in IntelliJ / VSCode)
  • editing
    • ys&#x3C;motion>&#x3C;character> wraps selected text in a specified character
    • cs&#x3C;old char>&#x3C;new char> changes the wrapped character around text under cursor from &#x3C;old char> to &#x3C;new char>
    • ds&#x3C;char> deletes wrapped character around text under cursor
    • gcc comments / uncomments the line
    • gc comments the selected block of text
    • &#x3C;Esc> in Normal mode sends nohlsearch to remove search highlights
    • &#x3C;leader>u shows a list of changes (undo tree), aka local file history
    • C-n / C-&#x3C;down> / C-&#x3C;up> creates a new cursor for the same word occurrences / below current cursor / above current cursor
  • LSP
    • S-k shows the hint for the symbol under cursor
    • &#x3C;leader>ca (built-in gra since NeoVim 0.11) shows c ode a ctions for the symbol under cursor in a Telescope panel
    • treesitter-textobjects provides custom scopes (like w for word or W for WORD ):
      • ac / ic - outer class code / inner class code
      • af / if - outer function / inner function
      • as - local scope
      • ai / ii - outer function call / inner function call ( i for invocation )
      • ap / ip - outer / inner parameter
      • ar / ir - outer / inner return statement
    • &#x3C;leader>o shows list of symbols defined in the current buffer (outline)
    • gr (built-in grr since NeoVim 0.11) shows a list of LSP references; &#x3C;C-q> sends the list of locations to quick buffer
    • gd shows a list of LSP definitions
    • gI (built-in gri since NeoVim 0.11) shows a list of LSP implementations
    • grn (built-in since NeoVim 0.11) renames a symbol under cursor
    • C-s (built-in since NeoVim 0.11) shows method signature reference
    • ]d / [d (built-in) goes to previous / next diagnostic message location (e.g. warnings, errors, suggestions in the code)
    • C-w,d shows the diagnostic message at cursor
  • Telescope
    • &#x3C;leader>&#x3C;leader> opens a quick action menu (Telescope builtin)
    • &#x3C;leader>f opens search in files
    • &#x3C;leader>gf opens search only in files tracked by Git
    • &#x3C;leader>b opens a list of NeoVim buffers, ignoring current buffer and sorting by last used timestamp
    • &#x3C;leader>/ performs a live-grep (with arguments) on files
    • C-q (in the search results; needs Zellij in the locked mode - C-g - to prevent conflict) moves files to quickref buffer; then
      • ]c / [c for next / previous quickref entry
      • &#x3C;leader>q toggles quickref buffer
      • &#x3C;leader>l toggles locations buffer

Aside from ridiculous amount of time spent configuring Neovim, it ticks most of my boxes:

  • Recent files ✅ &#x3C;leader>b
  • Go to declaration ✅ gd
  • Code completion ✅ ( nvim-cmp ) C-space
  • Syntax-aware selection ✅ ( nvim-treesitter with customized incremental_selection ): initialize treesitter selection mode with gsn and then increment / decrement node selection with gss and gsm
  • Find in files ✅ &#x3C;leader>/ ( telescope + telescope-live-grep-args , rg -powered)
  • Context actions ✅ gra
  • Find in current file ✅ /
  • Toggle comment ✅ gcc / gc&#x3C;object> (e.g. gcaw - comment word)
  • Go to file ✅ &#x3C;leader>f
  • Go to class ✅ &#x3C;leader>S ( telescope + LSP)
  • Rename ✅ grn
  • Find and replace in current file :%s/&#x3C;search>/&#x3C;replace>
  • Generate code ❌
  • Go to implementation ✅ gri
  • Introduce variable ❌
  • Change case ✅ ( text-case.nvim or through external program)
  • Implement methods ❌
  • Helix

    Helix

    Actually, my first try was Helix, but I immediately stumbled upon the first blocker - the task I was working on at that time involved some Mustache templates. And Helix did not support it even on the most basic level (syntax highlighting). Moreover, Helix did not have plugins at the time, so there was little I could do for that particular task. The reason I wanted at least syntax highlighting had to do with the issue I was working on, which had misplaced conditionals in the template file, resulting in an incorrect rendering. I liked, however, how Helix came with a lot of handy utilities out of the box - the file picker, treesitter integration (so I could jump between the rest of Java / TypeScript codebase with ease).

    I tried configuring a file tree via Yazi , which has an integration example on their website (using zellij terminal multiplexer panels), but it just refused to work for me on my Mac. That was when I timeboxed this and decided to switch my focus to NeoVim for the moment being.

    After a while of just living my life, a new version of Helix has dropped, 25.07. And it introduced a few quality o flife changes. For example, the file explorer, which is now built in. It is not as powerful as Yazi, but it does the job. So I decided to switch to Helix for a while.

    Upon getting back to Helix some time after, there was a new release, 25.07.1 which introduced a few quality of life improvements, including the file browser, sort of addressing the file tree issue I had before. Invoked with &#x3C;leader>e (compared to &#x3C;lead>f which just lists all the files in one long list), this one allows you to see directories. It is sort of an immediate-mode file manager as in it only shows the contents of a selected directory, but it is arguably more useful solution to the file tree problem than a list of all the files (recursively listing sub-directories). Additionally, tree-sitter was replaced so the syntax highlighting should be better - this would most likely be helpful in content like my blogs, often featuring multiple languages on top of the main Markdown.

    Something that I liked about Helix was how it handles selections. For the most part, native multi-cursor is a great start - you just have to remember the difference between splitting the selection and selecting inside the selection - S (split) vs s (select) - both would create multiple cursors, just in a different way.

    Different selection objects, including the ones provided by the tree-sitter - with the match mode you can select different objects ( ma and mi are your friends). But you can also surround the selection ( ms&#x3C;char> ) and change the surrounding ( mr&#x3C;from>&#x3C;to> ) and delete the surrounding ( md&#x3C;char> ), which I find pretty handy sometimes.

    Some things I find bearable are the use of external tools for some actions, instead of plugins. Since Helix lacks plugin system in any shape or form (as of late October 2025), you can just pipe the selection to the external program. One such case is changing the case of selection - I use this often , especially in conjunction with multiple cursors - to quickly edit, say test data or a bunch of constants or to refactor multiple class fields. In this case I found a comment on Github suggesting the use of ccase - you first need to install this Rust utility, ccase, and then you'll be able to send your selection(-s) by using :pipe ccase -t screamingsnake , for instance.

    Something I did not realize until writing this blog is that there are some really useful default keybindings for insert mode, like Ctrl+w to delete the previous word, Alt+w to delete the next word, Ctrl+k to delete to the end of the line and Ctrl+x to trigger autocomplete.

    One annoying thing about Helix is the buffer picker (available via &#x3C;lead>b ) - it shows the list of open buffers (files). It does not appear to be sorting the elements of the list and the first element is always the current buffer . This is not really helpful if you want to quickly go the previously edited file. To make things worse, it does not seem to have any configuration around it, so the behaviour is pretty much set in stone.

    I also am still missing one feature which made me try NeoVim in the first place, which is flash.nvim for quick jumps on the screen. Helix team did add something similar to HopWord command from hop.nvim , called goto_word , available via gw key shortcut. But unlike hop.nvim , Helix implementation is barely configurable (you can only configure the alphabet used for making labels) and comes with just one mode - HopWord . Additionally, it enforces exactly two-character abbreviations (jump labels). I thought this is rather limiting and since Helix is an open-source project, I decided to implement a behaviour similar to leap.nvim , since it is much less obstructive (it does not cover your entire screen in labels, making it super hard to figure out where you want to jump) and it allows to narrow down the places to jump by having prefix search. So I raised a PR and a suggestion discussion on Helix Github repo. To which the team just said "we don't want it" and dismissed the proposal:

    We made intentional choices when implementing the goto_word behavior. We were quite aware if the nvim plugins. We are not going to replace or add alternative commands

    One comment pointed to the plugin system when it is available:

    I'm not inclined to add more jumping commands as core Helix commands like gw. There are a lot of different spins on jumping functions in Neovim plugins and I believe that future work should be done in plugins (once available) rather than as core faetures.

    For context, plugin system has been discussed for over three years (as the moment of this writing, since September 2022) and apparently has been worked on for over two years (since October 2023). So I have no hope of seeing it released in the near future.

    But instead of giving up, I decided to give a try to this work-in-progress plugin system and after a week a flash.hx plugin was born.

    Here is my condensed cheatsheet of key shortcuts I use in Helix:

    • Pickers
      • &#x3C;lead>b buffer list
      • &#x3C;lead>e file explorer; far superior to file list
      • &#x3C;lead>/ search
      • &#x3C;lead>d show diagnostics (hints, errors, warnings, etc)
    • Multiple cursors
      • , collapse all cursors into one
      • s select in selection; create a new cursor at each selection; takes a regexp as a pattern
      • S split selection; create a new cursor at each occurrence of pattern; takes regexp as a pattern
    • Selection
      • v enters visual (selection) mode; this is how you can select multiple words - vwwww
      • m enters marking mode; this is how you can select paragraphs, text and LSP objects, add, change and remove wrapping characters (like brackets and quotes); few examples:
        • mi( - select inside parentheses
        • ma" - select everything inside double-quotes and the double-quotes themselves
        • ms[ - surround selection with square brackets
        • mr[( - replace the surrounding square brackets with regular braces
        • mif - select the body of a function (method)
      • = / &#x3C; / > - format / unindent / indent selection
      • :pipe or | - send selection to an external program and replace selection with the output of said program
        • as of version 25.7 you can also use interpolation with %{} , for instance, %{cursor_line} or %{buffer_name} , so you can pass in the filename to the external tool
      • % - select an entire buffer (file)
      • &#x3C;lead>&#x3C;c> / &#x3C;lead>&#x3C;C> - comment/uncomment the selection
    • Go to
      • gl / gh - go to end of line / start of line (contrary to $ and ^ in Vim)
      • gg / ge - go to first line / last line of the file
      • Ctrl+i / Ctrl+o - go back and forth in your jumplist (places where the cursor has been placed; jumplist itself is available with &#x3C;lead>j )
      • gd / gD - go to definition / declaration
      • gr - go to references
    • Copying (yanking)
      • "+y - copy to the OS clip buffer (translates to "change the buffer to the + - OS clipboard and then yank the selection")

    After a few weeks of working in Helix I was pleasantly surprised by how much out-of-the-box stuff it comes shipped with. And I did not have to spend a whole lot of time configuring it (aside from that week I spent developing flash.hx ).

    It checks most of my boxes too:

    • Recent files ✅ &#x3C;leader>b
    • Go to declaration ✅ gd
    • Code completion ✅ C-x
    • Syntax-aware selection ✅ m&#x3C;selection>&#x3C;see tooltip>
    • Find in files ✅ &#x3C;leader>/ (simplified)
    • Context actions ✅ &#x3C;leader>a (depends on LSP)
    • Find in current file ✅ /
    • Toggle comment ✅ &#x3C;leader>c
    • Go to file ✅ &#x3C;leader>f
    • Go to class ✅ &#x3C;leader>S (capital S for workspace symbols, lowercase s for current file symbols) (partial)
    • Rename ✅ &#x3C;leader>r
    • Find and replace in current file ⚠️ (unconventinal): select scope ( % for current buffer), then use s to select occurrences or S to split selections into multiple cursors, then use actions - i or c to change the selections, d to delete selections
    • Generate code ❌
    • Go to implementation ✅ gi (depends on LSP)
    • Introduce variable ❌
    • Change case ✅ (through external tool): select text, then | (pipe it), then specify external program ( ccase -t snake , for instance)
    • Implement methods ❌
    • Kakoune

      TBD

      Final thoughts

      I was surprised by how nice these seemingly limiting editors have become over the years (last time I used them was over-configured Emacs back in circa 2015)!

      Although rough around the edges and coming with massive pros and massive cons, both editors are being actively developed to become even nicer.

      Neovim:

      • 👍 comes with some quite nice things out of the box
      • 👎 the out-of-the-box niceities need LSP to be plugged in, which comes through a plugin manager
      • 👍 insane amount of plugins for all sorts of things
      • 👎 a proportionally insane amount of time required to find and configure the plugins to make for a comfortable experience
      • 👍 overall, the experience that you can create is on its own league
      • 👍 has a nice file tree implementation (yes, I like to see the structure of the directory and its parents)
      • 👍 has very nice semantic and LSP selection expand
      • 👍 has an OG Flash implementation
      • 👍 has nice surround behaviour
      • 👍 file picker powered by ripgrep so you can filter all you want
      • 👎 both selection expand and surround are a bit tricky to trigger ( gsn followed by gss ; ysaw" and cs[( and ds" )

      Helix:

      • 👍 comes with a ton of nice things out of the box
      • 👍 none of the niceities require extensive configuration (if any at all)
      • 👎 very slow development cycle, so new features do not come out often (like twice a year, I believe)
      • 👎 no plugin system, making the new features even less frequent or even possible
      • 👎 very strongly opinionated developers, so if you are not comfortable with a feature - tough luck!
      • 👎 does not have file tree
      • 👎 file picker is very basic - only offers filtering by partial path match
      • 👎 semantic selection expansion is not exactly expansion , but more like "select this exact scope"
      • 👍 surround and semantic selection triggers are consistent e.g. make much more sense ( ms( , mr([ , md[ ; maf , maa )

      My current stance is that Neovim is a much stronger contender with a much broader set of (much better implemented) features, but the amount of time you have to spend to get to that state is enormous. And whilst much nicely organised out of the box, Helix is very much undercooked (in my opinion).

      Hence, for powerful and actual workloads - use Neovim, it is worth spending all that time configuring it for that purpose. For a casual relaxing but very restricted editing - Helix is an-okay choice.

Strongly-typed front-end: experiment 2, simple application, in Gleam / Lustre urn:uuid:e6ec01e4-5bb7-5d9d-b16e-5887d6fd3003 2024-12-20T00:00:00Z 2024-12-20T00:00:00Z Strongly-typed front-end: experiment 2, simple application, in Gleam / Lustre Artem Shubovych

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">float</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option.{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">None</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lustre</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lustre</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attribute.{value}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lustre</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">element.{text}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lustre</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">element</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">html.{button, div, input, p, select}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lustre</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event.{on_click, on_input}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  Circle</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  Square</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">s: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">x: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  CalculateArea</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">shape: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">), </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">area: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.14</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> calculate_area</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">shape: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">x: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    Circle</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">*.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    Square</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">*.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> init</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_flags</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">shape: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">None</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value: </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">area: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">None</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">model: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">msg: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Msg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(s) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">..</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">model, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">shape: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(v) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">..</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">model, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    CalculateArea</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">      State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        ..</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">model,</span></span>
<span class="line"><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">        area: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(model.shape, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(s) { </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculate_area</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(s, model.value) }),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> handle_value_change</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">s: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_empty</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(s) {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    True</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    False</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> float.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(s) {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">        Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> handle_shape_change</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">s: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">None</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> view</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">model: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  div</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([], [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">on_input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(handle_shape_change)], [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      html.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)], </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      html.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)], </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      html.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)], </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(float.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(model.value)), </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">on_input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(handle_value_change)]),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    button</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">on_click</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CalculateArea</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)], [</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Calculate area"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)]),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    p</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([], [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "Area: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> option.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unwrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(option.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(model.area, float.to_string), </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> app </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lustre.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">simple</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(init, update, view)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> assert</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lustre.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(app, </span><span style="color:#40A02B;--shiki-dark:#A6D189">"#app"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Nil</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  Nil</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

Resulting bundle is quite big sitting at a whopping 65.9kb

Iterating a vector in C++ urn:uuid:ad7053e1-a00f-5864-b8a7-a5bedb43bbaf 2024-10-31T00:00:00Z 2024-10-31T00:00:00Z Iterating a vector in C++ Artem Shubovych

Such a simple topic - iterating over a vector, is it even worth discussing?

Interestingly enough, there is a difference in how exactly you iterate - be it using iterators, for(:) sugar or plain old for(i=0; i&#x3C;vec.size(); ++i) .

Let us see what output does a compiler produce in each of these cases.

sample1 (simple for loop):

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movsx</span><span style="color:#D20F39;--shiki-dark:#E78284">   rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">    std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> >::operator[](unsigned long)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movsx</span><span style="color:#D20F39;--shiki-dark:#E78284">   rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">    std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> >::size() const</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        setb</span><span style="color:#D20F39;--shiki-dark:#E78284">    al</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    al</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">al</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L4</span></span></code>

but

sample2 (reversed for loop):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> --</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">    std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> >::size() const</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sub</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">    std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> >::operator[](unsigned long)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L3</span></span></code>

also

sample3 (foreach):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">80</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">    std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> >::begin()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">88</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">    std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> >::end()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">96</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">88</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    __gnu_cxx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:__normal_iterator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> > >::operator*() const</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">28</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">28</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">88</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    __gnu_cxx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:__normal_iterator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> > >::operator++()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">96</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">88</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bool </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">__gnu_cxx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:operator!=&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> > >(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">__gnu_cxx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:__normal_iterator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> > > const&#x26;, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">__gnu_cxx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:__normal_iterator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::vector&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::allocator&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">> > > const&#x26;)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    al</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">al</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L4</span></span></code>

but with -O1

sample1 (simple for loop):

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">12884901893</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4294967298</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L10</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .L19</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L20</span></span></code>

sample2 (reversed for loop):

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">12884901893</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4294967298</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sub</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L8</span></span></code>

sample3 (foreach):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">12884901893</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4294967298</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L10</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .L19</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L20</span></span></code>

Interesting how iterating forwards adds an extra boundary check and a jump ( cmd rbx, rbp and je .L19 in samples #1 and #3), whereas iterating backwards does not.

But this find actually must come with one pretty big caveat: the cache lines. The number of assembly instructions is a pretty poor measure of performance - after all, CPU instructions are ridiculously fast, compared to any form of IO - specifically memory access.

The code is also available on Github: [ https://github.com/shybovycha/iterate-over-vector-in-cpp/ ]

The benchmarking results seem to prove the assumption: bacwards iteration seems to be faster:

Test Min Max 50% 90% 95% delta
sample1 ( ++i ) 1325447 3762733 1339309 1416805 1429724 +7%
sample2 ( --i ) 1290571 2596630 1308953 1334955 1342008 0%
sample3 ( for(:) ) 1438847 3034474 1460698 1506001 1508657 +11%

Out of curiosity, I also benchmarked using the postfix operator instead of prefix: i++ (postfix) instead of ++i (prefix), which shows prefix operator is slightly faster:

Test Min Max 50% 90% 95% delta
sample1 prefix ( ++i ) 1325447 3762733 1339309 1416805 1429724 +11%
sample1 postfix ( i++ ) 1292195 4155596 1308721 1370542 1382136 +7%
sample2 prefix ( --i ) 1290571 2596630 1308953 1334955 1342008 +5%
sample2 postfix ( i-- ) 1256929 2598426 1267088 1277779 1282787 0%

Interestingly enough, there is some difference:

  1. backward iteration with postfix decrement for (auto i=vec.size()-1; i>0; i--) is the fastest
  2. backward iteration with prefix decrement --i is
  • 5% slower than i--
  1. forward iteration with postfix increment i++ is
  • 3% slower than --i
  • 7% slower than i--
  1. forward iteration with prefix increment ++i is the slowest:
  • 11% slower than i--
  • 7% slower than --i
  • 4% slower than i++

The above tests were ran 10000 times on a heap-allocated ( std::vector ) 10000 int elements.

Standard library iterators

Out of sheer curiosity, I decided to test how using an iterator would affect the results ( sample4 ):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">it</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">it</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

With both prefix and suffix (postfix) variations:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">it</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And the reverse iterator ( sample5 ):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it</span><span style="color:#179299;--shiki-dark:#81C8BE">--</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">it</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Test Min Max 50% 90% 95% delta
sample1 prefix ( ++i ) 1325447 3762733 1339309 1416805 1429724 +11%
sample1 postfix ( i++ ) 1292195 4155596 1308721 1370542 1382136 +7%
sample2 prefix ( --i ) 1290571 2596630 1308953 1334955 1342008 +4%
sample2 postfix ( i-- ) 1256929 2598426 1267088 1277779 1282787 0%
sample3 ( for(:) ) 1438847 3034474 1460698 1506001 1508657 +17%
sample4 prefix ( ++it ) 1470583 2834386 1495310 1561023 1564850 +22%
sample4 postfix ( it++ ) 1461634 2695552 1535905 1547865 1556815 +21%
sample5 prefix ( --it ) 1462156 2802714 1470567 1478957 1512621 +18%
sample5 postfix ( it-- ) 1447920 2831859 1471334 1479670 1490088 +16%

The results are a bit surprising, looking at the assembly code generated by G++:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .L10</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L11</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L27</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .L26</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L27</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L26</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    r13</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .L18</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sub</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    operator delete(void*, unsigned long)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; ... cleanup &#x26; exit ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        ret</span></span></code>

Clang 17.0.1 is a slightly different story:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sub</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">9223372036854775804</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     qword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ptr [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .LBB0_11</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r14</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sar</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        adc</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rcx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jbe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_14</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jae</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_16</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_17</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .LBB0_18</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_19</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    operator new(unsigned long)@PLT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     r15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_21</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rcx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .LBB0_17</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rcx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_19</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        xor</span><span style="color:#D20F39;--shiki-dark:#E78284">     r15d</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r15d</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_21</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     dword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ptr [</span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">r13d</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r14</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">qword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ptr [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_23</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r14</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    memmove@PLT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_23</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    rbx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .LBB0_25</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    operator delete(void*)@PLT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        movabs  </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2305843009213693951</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_26</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     r15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r14</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .LBB0_7</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> - </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">dword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ptr [</span><span style="color:#D20F39;--shiki-dark:#E78284">r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    moo(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)@PLT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_5</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    r15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .LBB0_9</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    operator delete(void*)@PLT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        xor</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pop</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pop</span><span style="color:#D20F39;--shiki-dark:#E78284">     r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pop</span><span style="color:#D20F39;--shiki-dark:#E78284">     r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pop</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pop</span><span style="color:#D20F39;--shiki-dark:#E78284">     r15</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pop</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        ret</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rip</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + .L.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">str.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">    std</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::__throw_length_error(char const*)@PLT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_30</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .LBB0_30</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     qword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ptr [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">r15</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     r14</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     qword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ptr [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        je</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      .LBB0_32</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">qword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ptr [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    operator delete(void*)@PLT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LBB0_32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r14</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _Unwind_Resume@PLT</span></span></code>

Caching impact

One other assumption is that iterating over a vector backwards affects the memory caching in a pretty poor manner. This is a rather complex scenario to test, since there are two potential scenarios on how this could happen:

  1. swap memory usage - happens when the dataset is so big it does not fit in the available RAM and OS has to switch to using disk instead of RAM; this is the worst-case scenario
  2. data locality / CPU cache usage - CPUs usually try to predict memory access patterns and pre-load more data than actually required by a given operation; when the data block is accessed at random points (indices), CPU fails to pre-load the correct slices of memory

Since this blog is about iterating over a vector, it would be seem to be easier to generate absurdely large chunks of data and try to iterate over them. But in reality it would only happen with absurdely large files - my machine, for instance, sports 32GB of RAM, so it would be quite a task to generate multiple 32GB files.

Simulating random memory access will break the purpose of iterating over the elements one by one - in these cases we either use iterators to access a linked list (each element is in random part of RAM) or access elements by index. And there is no way to iterate over them by incrementing an index. Alternatively, we have to dereference indexes from another block of memory. Either way it has nothing to do comparing for loops.

Simulating accessing multiple cache lines could actually be easier - we just need to replace integers with structures of variable size and use std::list (linked list) instead of std::vector (single block of memory):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyStruct</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 1 byte</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // sizeof(float) * 100 = 4 * 100 = 400 bytes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  double</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">53</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // sizeof(double) * 53 = 8 * 53 = 424 bytes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  char</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // sizeof(char) * 64 = 1 * 64 = 64 bytes</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // total size = 889 bytes, likely to span across multiple cache lines</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">list</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MyStruct</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

and generate a large enough number of these objects:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;random></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">random_device rd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">mt19937_64</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> gen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">uniform_int_distribution</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> bool_dist</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">uniform_real_distribution</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> float_dist</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1000.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">uniform_int_distribution</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> int_dist</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">numeric_limits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">numeric_limits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  MyStruct e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">bool</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bool_dist</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> float_dist</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 53</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">double</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">float_dist</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 64</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">int_dist</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Just to prevent memory leaks, cleanup the test data at the end:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  delete</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">clear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

These benchmarks take significantly longer time to run and produce big numbers:

Test Min Max 50% 90% 95% delta
sample1 ( ++i ) 7882057 15385569 7948012 8004355 8031673 0%
sample2 ( --i ) 7915870 16297070 8971293 9109493 9151567 +13%
sample3 ( for(:) ) 8094894 16496526 8159004 8229138 8259364 +3%

Compare this to a structure which actually fits in one cache line. Cache line size is apparently 64 B - that is sixty-four bytes - on most CPUs ( AMD Zen , Intel Ice Lake ). My Apple M1 laptop has twice as much, 128 B , as shown by running sysctl -a | grep 'hw.cachelinesize' .

If the structure was reorganized to fit in that limit, like so:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyStruct</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 1 byte</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  float</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // sizeof(float*) = 8 bytes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  double</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // sizeof(double*) = 8 bytes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  char</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // sizeof(char*) = 8 bytes</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // total size = 25 bytes, likely to fir in a single cache line</span></span></code>

The timings are considerably lower for the backwards iteration:

Test Min Max 50% 90% 95% delta
sample1 ( ++i ) 7575860 20005185 7640651 7700057 7725933 0%
sample2 ( --i ) 7466816 18068148 7657415 8109531 8208603 +6%
sample3 ( for(:) ) 7832724 14264212 7882930 7932295 7960718 +3%

This highlights how predictive cache loading and data element size that fits into a single CPU cache line actually impacts RAM reads - by a significant margin.

Conclusion

In simplest case (vector of numbers), the worst case scenario is within 11% difference, with backwards iteration being the fastest, followed by forward iteration and foreach being the slowest of the bunch. Prefix decrement in the backwards iteration being the fastest. Bear in mind: these numbers are in nanoseconds , meaning the worst case scenario is 10000 (ten thousand) elements of variable size being iterated in 1.5 ms and the fastest being 1.3 ms - that is milliseconds . For comparison, rendering a frame at 120 FPS rate would take about 8.3 ms . And if you were to process some requests (in a client-server system), you would be able to handle 699 requests per second while iterating over this list. So realistically, the way you iterate a vector of integers, any of these techniques would only really matter if you are working on a really high performance system.

That being said, this is all true while the vector elements fit in one CPU cache line or cache block, that is L1 and L2 caches.

So if the data element does not fit in a block of 64 B (or 128 B on some CPUs), the performance impact of backwards iteration is going to be more significant. In this case we are talking about 8 ms vs 9.1 ms . In terms of FPS, the difference would be 125 FPS vs 109 FPS . Or about 15 requests per second more.

Gantt chart. Part 4 urn:uuid:bbce72fa-a6ae-513c-bb10-e58a764d19b0 2024-06-27T00:00:00Z 2024-06-27T00:00:00Z Gantt chart. Part 4 Artem Shubovych

Contents

Seems like every two years or so I hop on my Gantt chart implementation and rework it completely.

Last few attempts ( rev. 1 , rev. 2 , rev. 3 ) were alright, but I was never quite satisfied with the implementation - be it SVG, which has a toll on a browser and has quite limited customization functionality or Canvas API, with same limited customization but being fast.

With the recent introduction of grid layouts in CSS, now supported in all browsers , now seems like a perfect time to revisit the old implementations once again:

Gantt chart, revision 4

CodeSandbox / live demo

This revision now has a proper horizontal scrolling on the panel with bars - meaning the labels on the left panel stay in place whilst the left panel is scrollable. Moreover, the chart is now relies on pure HTML and CSS (being rendered with React though), making it is possible to use rich markup inside the bars and labels.

Implementation steps

The data for the tests is going to look like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "epic 1"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "epic 2"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "epic 3"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "story 1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "story 2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "story 3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "story 4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "story 5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "lorem ipsum dolor atata"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "task 2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The main component, &#x3C;Gantt> , initially was implementated as follows:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> useMemo </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "react"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> style </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "./gantt.module.css"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> LeftPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> LeftPane</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left_pane_header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">/</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">LeftPaneRow</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> key</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPane</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane_header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">...scale...</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRow</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> key</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> flattenTree</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visited </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">shift</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (visited</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">has</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    visited</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    items</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> child</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unshift</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(child))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Gantt</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> itemList </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useMemo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> flattenTree</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [items])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">LeftPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

The core of the proper representation of this diagram is the CSS:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> / auto </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template-areas</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "left right"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100%</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">left_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  border-right</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> solid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bbb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> auto </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> / </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template-areas</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "corner"</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "rows"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">left_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">left_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">left_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">left_pane_header</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> corner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> auto </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> / </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template-areas</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "scale"</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "rows"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  overflow</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> auto</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10000</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> /*temp*/</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_header</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  height</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 40</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  align-items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  position</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> relative</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  position</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> absolute</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  background</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">eeeeee</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  padding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  border-radius</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.4</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Split into two panels, right is scrollable

Good, we now have two panels with items aligned in rows and the right panel being scrollable if it gets really long. Next thing, position: absolute is absolutely disgusting - we use grid layout already! Instead, split each row into the same number of columns using grid and position the elements in there:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gridTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `auto / repeat(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">, 1fr)`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gridArea </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `1 / </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> / 1 / </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gridTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          gridArea</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      ></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

and clean up the CSS a bit (like removing the position: absolute and reducing the width from 10000px down to 1000px ):

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1000</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> /*temp*/</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  height</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 40</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  align-items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  position</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> relative</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  background</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">eeeeee</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  padding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  border-radius</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.4</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now, let's position the elements in each row using the column index:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPanelRowEntry</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gridArea </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `1 / </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> / 1 / </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gridArea</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gridTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `auto / repeat(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">, 1fr)`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gridArea </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `1 / </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> / 1 / </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gridTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          gridArea</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      ></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPaneHeaderRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gridTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `auto / repeat(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">, 1fr)`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane_header_row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gridTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPaneHeader</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane_header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPane</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columnHeaders </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(columns)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> idx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeader</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">idx </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeader</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRow</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> key</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPanelRowEntry</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPanelRowEntry</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeaderRow</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columnHeaders</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeaderRow</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

And add corresponding new CSS styles:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_header_row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_header_row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_header</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  align-items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  text-align</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This requires start and end defined for each entry:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "epic 1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    start</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    end</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "epic 2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    start</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    end</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "epic 3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    start</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    end</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "story 1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    start</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    end</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">};</span></span></code>
Aligning items in a grid

And, to make it not repeat a dozen of inline CSS styles, we can utilize CSS variables:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPanelRowEntry</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "--col-start"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "--col-end"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPane</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columnHeaders </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(columns)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> idx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeader</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">idx </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeader</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRow</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> key</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPanelRowEntry</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPanelRowEntry</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "--columns"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columns </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeaderRow</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columnHeaders</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeaderRow</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

We can also re-use the same row for header:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPaneHeaderRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right_pane_header_row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

And corresponding CSS:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_header_row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> auto / </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">--columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  position</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> relative</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-template</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> auto / </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">--columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">entry</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  background</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">eeeeee</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  padding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  border-radius</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  align-items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  text-align</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  grid-area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> / </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">--col-start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> / </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> / </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">--col-end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

I like to also change the fonts, since the default sans-serif just looks terrible:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">@import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://fonts.googleapis.com/css2?family=Assistant:[email protected]&#x26;display=swap"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#179299;--shiki-dark:#81C8BE">root</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  font-family</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Assistant"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sans-serif</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  font-optical-sizing</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> auto</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  font-weight</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 300</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  font-style</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  font-variation-settings</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "wdth"</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Changing the font

And maybe add some grid lines for the rows:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#179299;--shiki-dark:#81C8BE">first-child</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  border-top</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> solid </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">--border-color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">eee</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  padding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.75</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  border-bottom</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> solid </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">--border-color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">eee</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Adding grid lines

Now let's add some padding to separate parent and child items of a chart:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> LeftPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> level</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nestingPadding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">level</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">rem`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "--label-padding"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nestingPadding </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>
<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">left_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  padding-left</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> var</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">--label-padding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

and fill out the level property when flattening the item tree:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> flattenTree</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  items</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> level</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visited </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> level</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">shift</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (visited</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">has</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> level </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    visited</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    items</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> child</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unshift</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> level</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> level </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>
Shrinking right panel

And automate the number of columns calculation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Gantt</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> itemList </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> flattenTree</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> startsAndEnds </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatMap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columns </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startsAndEnds) </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startsAndEnds)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">LeftPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

In order to make chart panel scrollable, one can set a width CSS property for the .right_pane_rows and .right_pane_header_row :

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2000</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">right_pane_header_row</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2000</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The last bit for a this prototype would be to have a scale for the columns.

Assume a chart item has an abstract start and end fields - these could be dates or some domain-specific numbers (like a week in a quarter or a sprint, etc.). Those will then need to be mapped onto column index. Then the chart width (in columns) would be the difference between the smallest start value and the biggest end value:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Gantt</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> itemList </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> flattenTree</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ...</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // assuming `scale` function returns an object { start: number; end: number }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStartItem </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> minBy</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxEndItem </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> maxBy</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columns </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxEndItem</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStartItem</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">LeftPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

The minBy and maxBy helper functions could be either taken from lodash or manually defined like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> minBy</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> selector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minIndex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">selector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> selector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items[minIndex])) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      minIndex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items[minIndex]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

For better navigation around this code we can add some types:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartItem</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartProps</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartItem[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  scale</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartItem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> start</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> end</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> minBy</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">T</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> T[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> selector</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> T</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Gantt</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartProps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> default</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> scale</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Gantt</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> items</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> scale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

We can extend this even further by adding an API to provide labels for columns:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartProps</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">column</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Gantt</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartProps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">LeftPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPane</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columnHeaders </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(columns)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> idx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeader</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scaleLabel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(idx)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneHeader</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> default</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> scale</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">col</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#40A02B;--shiki-dark:#A6D189"> `</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">col</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Gantt</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> scale</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

This new API can then be utilized to show month names, for instance:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> default</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> scale</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#E64553;--shiki-dark:#EA999C"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> months </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Jan"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Feb"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Mar"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Apr"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "May"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Jun"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Jul"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Aug"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Sep"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Oct"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Nov"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Dec"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">col</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#E64553;--shiki-dark:#EA999C"> months</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#E64553;--shiki-dark:#EA999C">col</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Gantt</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> scale</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C">scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C">scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Adding scale with labels

Moreover, it is now possible to inline HTML and CSS in the name of each chart item:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> LeftPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> level</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nestingPadding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">level</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">rem`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> style</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "--label-padding"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nestingPadding </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">span</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> dangerouslySetInnerHTML</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__html</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">span</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

And then in data.json (note that FontAwesome requires its CSS on a page in order to work):

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> '&#x3C;i style=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"font-family: \'FontAwesome\';"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"fa fa-car"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">>&#x3C;/i>&#x26;nbsp;story with FontAwesome'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 'inline &#x3C;em>&#x3C;b style=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"color: #5ebebe"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">>CSS&#x3C;/b> color&#x3C;/em> &#x3C;u style=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"border: 1px dashed #bebefe; padding: 2px; border-radius: 2px"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">>works&#x3C;/u>'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span></code>

The API can be further improved by providing the render function for the bars' labels:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> RightPane</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> barLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRow</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> key</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRowEntry</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">barLabel </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> barLabel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item) </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/></span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRowEntry</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPaneRow</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartProps</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartItem[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  scale</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartItem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> start</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> end</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">column</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  barLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartItem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Chart</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  items</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  barLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> GanttChartProps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">style</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gantt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">LeftPane</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">RightPane</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">itemList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        columns</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        barLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">barLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

and then in App component:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pluralize </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "pluralize"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> default</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> barLabel</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#E64553;--shiki-dark:#EA999C">end</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#E64553;--shiki-dark:#EA999C"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pluralize</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"month"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> end</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#E64553;--shiki-dark:#EA999C"> start</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Chart</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      items</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      scale</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C">scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      scaleLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C">scaleLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      barLabel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#E64553;--shiki-dark:#EA999C">barLabel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    /></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>
More customized labels
So why Redux is bad? urn:uuid:08996413-4fb3-5d7f-a0df-886f1a672358 2024-06-26T00:00:00Z 2024-06-26T00:00:00Z So why Redux is bad? Artem Shubovych

Redux is generally considered a bad choice for state management on front-end. But check out an average application' React application (or a few fragments of it):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Provider</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> useAtom </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'jotai'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> useQuery </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'react-query'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useInfo</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isLoading </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useQuery</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    queryKey</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'info'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    queryFn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/info'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">json</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    staleTime</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> Infinity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    info</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    isLoading</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> HomeWithoutProvider</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> raiseToast </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useToast</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> initialRender</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> setInitialRender </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">false</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> setPageType </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useAtom</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(pageTypeAtom)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useInfo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  useEffect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (info</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isNewVersionAvailable) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      raiseToast</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [info])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">...</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Home</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Provider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">HomeWithoutProvider</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Provider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Routes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">BrowserRouter</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Suspense</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> fallback</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Loader</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Route</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> element</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Home</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> path</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Suspense</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">BrowserRouter</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createRoot</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getElementById</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'root'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">root</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">StrictMode</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">StyleThemeProvider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">ToastProvider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">GlobalErrorHandler</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">ReactQueryProvider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Routes</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">ReactQueryProvider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">GlobalErrorHandler</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">ToastProvider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">StyleThemeProvider</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">StrictMode</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Usually most of the components ( Home , Routes ) and hooks ( useInfo ) are in separate files, but for the sake of simplicity I combined them all into one code block.

What I find suboptimal with this code is that it has at least three obvious different state management systems:

  • jotai for shared atoms (pieces of global state)
  • React.useState for internal component state
  • various React.Context s ( StyleThemeProvider , ToastProvider , GlobalErrorHandler , etc.)

On top of those, there are less obvious state management systems:

  • react-router uses internal router state, which could be treated as global application state
  • react-query uses its internal cache for each query
  • react-hook-form uses the form state of a component' ancestor (which could be declared on any level above the current component)

In the pursuit of encapsulation and reducing the boilerplate, front-end developers came up with all of these solutions aiming to solve the problem of managing application state.

So what exactly is this problem? And what are the issues all of the aforementioned solutions try to address?

As I see it, there are two competing camps:

  • containing the logic in small reusable chunks (hooks, components)
  • sharing chunks of state between different parts of the application

There are some side-tracks like dealing with asynchronous actions (like fetching the data from server), changing the state of external components (like showing a toast message), reducing the unnecessary re-renders.

Back in the day, Redux seemingly addressed these areas to a degree. Redux implements Flux architecture, which was compared to MVC (Model-View-Controller) architecture back in the day:

Data flow in MVC architecture Data flow in Flux architecture

It became especially popular after Angular.JS' MVVM (Model-View-ViewModel) architecture implementation was considered slow with its dirty checks and constant re-rendering.

It could be said that Redux is being shipped in recent versions of React itself - with the use of useReducer() hook. One would rarely use Redux on its own, often sticking to a somewhat opinionated stack of reselect (for derived state), react-redux (to connect() components to the store) and redux-thunk or redux-sagas (for asynchronous dispatch() calls).

The aforementioned component could be implemented with the "conventional" (old) Redux approach like so:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createStore</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> combineReducers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> applyMiddleware </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'redux'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> connect </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'react-redux'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createSelector </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'reselect'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thunk </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'redux-thunk'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> infoReducer</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNewVersionAvailable</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  switch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INFO_LOADED'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">payload </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pageDataReducer</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageType</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  switch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SET_PAGE_TYPE'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageType</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pageType </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toastReducer</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isOpen</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  switch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SHOW_TOAST'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isOpen</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">payload </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rootReducer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> combineReducers</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  info</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> infoReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  pageData</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageDataReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  toast</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> toastReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createStore</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(rootReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> applyMiddleware</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(thunk))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// Meet thunks.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// A thunk in this context is a function that can be dispatched to perform async</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// activity and can dispatch actions and read state.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// This is an action creator that returns a thunk:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loadInfoAction</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/info'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">json)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">payload</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INFO_LOADED'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> payload </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> raiseToastAction</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SHOW_TOAST'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> payload</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setPageTypeAction</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">pageType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SET_PAGE_TYPE'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageType </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Home</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> pageType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> loadInfo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> raiseToast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> setPageType</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  useEffect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    loadInfo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  useEffect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (info</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isNewVersionAvailable) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      raiseToast</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [info])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">...</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mapStateToProps</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> pageType</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageType </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mapDispatchToProps</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  raiseToast</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">raiseToastAction</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(content))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  setPageType</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">pageType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPageTypeAction</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(content))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  loadInfo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loadInfoAction</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HomeContainer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> connect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(mapStateToProps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mapDispatchToProps)(Home)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Routes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">BrowserRouter</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Suspense</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> fallback</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Loader</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Route</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> element</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">HomeContainer</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> path</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Suspense</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">BrowserRouter</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createRoot</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getElementById</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'root'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">root</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">Routes</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

In my opinion, Redux is not suitable for complex projects for a few reasons:

  • it combines all states (both local and global) in one big messy furball; managing it is quite a hurdle
    • as the project complexity grows, one can not just change a piece of state or selectors without affecting the entirety of the project (and teams)
    • combining reducers into one supermassive function makes any state update unreasonably long and complex process (remember: each reducer returns a new state instance; now imagine having even a hundred of reducers, each of which returns a new state)
  • it is easy for a component to be re-rendered on any change to the state; a lot of effort goes into making sure selectors are well memoized and not re-calculated
  • asynchronous actions are a big unsolved mystery (are you going to use thunks, flux, sagas or something else?)

On a flip side, the idea itself could actually bring a lot of positives if cooked properly:

  • there is only one possible flow of data: via dispatch() call, through the reducers and back to the components connected to the store via component props
    • this is supposed to make following the data (e.g. debugging the application) easy
  • components are pretty much stateless at this point, encapsulated and not having side effects leaking everywhere
  • logic is nicely separated from the representation and is encapsulated in the reducers (and maybe, to a small extent, in selectors)

Elm utilizes the language features and its own runtime combined with Redux-like architecture to improve some aspects of the more traditional pure JS way of things, where there are only opinionated libraries and no one way of doing things.

Consider Elm architecture and how it compares to Redux:

  • all the states are still combined into one big cauldron of chaos
  • by default, any component is just a function returning an array; the entire application will be rerendered on each state change, which is still suboptimal, since literally all components are connected to the store
  • asynchronous actions are handled separately by the runtime in a similar way to synchronous actions; each action returns a new state and a command (triggering the asynchronous processing)
    • since commands are handled by the runtime and there's a handful of commands, all of them will (eventually) circle back to dispatching messages just like components do, following the same one-way data flow
  • reducers are a lot faster, since they are essentially a big switch..case statement (which is cheap)

The above component could be re-implemented in Elm as follows:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Browser</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exposing</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (..)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Attributes</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exposing</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Events</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exposing</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (..)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Http</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Json</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Decode</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exposing</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Decoder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">field</span><span style="color:#7C7F93;--shiki-dark:#949CBB">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Browser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">element</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> init </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> init</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> subscriptions </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> subscriptions</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type alias Model</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  { </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">info </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Result</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Http</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Info</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  , </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">toast </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Toast</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  , </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pageType </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> PageType</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type alias Info</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  { </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">quote </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  , </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">source </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  , </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">author </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  , </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">year </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Int</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type alias Toast</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  { </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">content </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type PageType</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Page1</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Page2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">init</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Cmd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">init</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> _</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> toast </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Page1 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loadInfo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type Msg</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GotInfo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Result</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Http</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Info</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShowToast</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Toast</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> SetPageType</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> PageType</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">update</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Model</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Cmd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">update</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    GotInfo result </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      case </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Ok info </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Ok info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Err e </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Err e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ShowToast t </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> toast </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just t </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    SetPageType p </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pageType </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">subscriptions</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Model</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Sub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">subscriptions</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Sub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">view</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Model</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">view</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> h2 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Demo App"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> viewInfo model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">info</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> viewToast model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">toast</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">viewInfo</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Result</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Http</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">viewInfo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mbInfoResult </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mbInfoResult </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Nothing </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Loading..."</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Just infoResult </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      case </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">infoResult </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Err </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">_</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Could not load info"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Ok info </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"App loaded"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">viewToast</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Toast</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">viewToast</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mbToast </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mbToast </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Nothing </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Just toast </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text toast</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">content </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loadInfo</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Cmd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loadInfo</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Http</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">get</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "/info"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> expect </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Http</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">expectJson GotInfo infoDecoder</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">infoDecoder</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Decoder</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Info</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">infoDecoder</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  map Info</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">field </span><span style="color:#40A02B;--shiki-dark:#A6D189">"isNewVersionAvailable"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

The good bits are:

  • forcing to handle all possible actions (messages) and results (HTTP success and error scenarios)
  • expressive language features (union types, strong typing, records, switch-case expressions) ensure robust code (as in this code does not leave room for mistakes like null/undefined/unhandled exceptions/unhandled code path/wrong value type)
  • no leeway for various ways to get things done (as in there is only one way to handle HTTP requests, only one way to handle asynchronous message dispatches, only one way to parse HTTP responses)

But if Redux spreads things apart compared to modern React, Elm feels like it spreads things further apart by handling effect results separately (like sending HTTP request, parsing HTTP response and processing the result by dispatching another message).

One other example would be PureScript (or rather Halogen ). Purescript itself elevates the complexity to the skies and beyond, by making you run around with monads like a headless chicken. Consider "simple" example of sending a HTTP request:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Affjax.Web </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AX</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Affjax.ResponseFormat </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AXRF</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Either (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hush</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect.Aff.Class (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> H</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.Aff (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">awaitBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> runHalogenAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Events </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Properties </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HP</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.VDom.Driver (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runUI</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.Event.Event (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Event</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.Event.Event </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Event</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runHalogenAff </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> awaitBody</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  runUI component unit body</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  {</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> loading </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Boolean</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> result </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe String</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> SetUsername</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> MakeRequest</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Event</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">component</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> query input output m</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> H.Component</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> query input output m</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">component </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkComponent</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    { initialState</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eval</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkEval </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">defaultEval { handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handleAction }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">initialState</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">initialState _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { loading</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> H.ComponentHTML</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> () m</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">render st </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">form</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onSubmit </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ev </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> MakeRequest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ev ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h1_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Look up GitHub user"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">label_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Enter username:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">username</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueInput </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> SetUsername</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">disabled st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">loading</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type_ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP.ButtonSubmit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Fetch info"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">loading </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">then</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Working..."</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          Nothing</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h2_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Response:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pre_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text res ] ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handleAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> output m</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> H.HalogenM</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> () output m </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  SetUsername</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ _ { username </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  MakeRequest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">liftEffect </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Event</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">preventDefault event</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gets _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">username</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ _ { loading </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    response </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">liftAff </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> AX</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">get </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">AXRF</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://api.github.com/users/"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ _ { loading </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> map _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body (hush response) }</span></span></code>

Now add the halogen-store package to the mix to make use of Redux-like state management:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Affjax.Web </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AX</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Affjax.ResponseFormat </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AXRF</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Either (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hush</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect.Aff.Class (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> H</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.Aff </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HA</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Events </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Properties </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HP</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.VDom.Driver (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runUI</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.Event.Event (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Event</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.Event.Event </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Event</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.Store.Monad (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadStore</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> updateStore</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> runStoreT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.Store.Connect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Connected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> connect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.Store.Select (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">selectAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect.Aff (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">launchAff_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StoreAction</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreSetUsername</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreMakeRequest</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreReceiveResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StoreAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reduce store </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  StoreSetUsername</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    store { username </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  StoreMakeRequest</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    store { loading </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  StoreReceiveResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    store { loading </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">initialStore</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">initialStore </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { username</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loading</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> launchAff_ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HA</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">awaitBody</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  root </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runStoreT initialStore reduce component</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  void </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runUI root unit body</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  {</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> loading </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Boolean</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> result </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe String</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> SetUsername</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> MakeRequest</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Event</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ReceiveState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Connected</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deriveState</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Connected</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deriveState { context</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { username</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loading</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ } </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  { username</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loading</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loading</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">component</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> query output m</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadStore</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StoreAction</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> H.Component</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> query </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Unit</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> output m</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">component </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  connect selectAll </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkComponent</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    { initialState</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveState</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eval</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkEval </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">defaultEval</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handleAction</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> receive </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ReceiveState</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> H.ComponentHTML</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> () m</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">render st </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">form</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onSubmit </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ev </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> MakeRequest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ev ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h1_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Look up GitHub user"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">label_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Enter username:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">username</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueInput </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> SetUsername</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">disabled st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">loading</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type_ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP.ButtonSubmit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Fetch info"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">loading </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">then</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Working..."</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> st</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          Nothing</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h2_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Response:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pre_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text res ] ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handleAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> output m</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadStore</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StoreAction</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> H.HalogenM</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> () output m </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  SetUsername</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    updateStore </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreSetUsername</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  MakeRequest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">liftEffect </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Event</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">preventDefault event</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gets _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">username</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    updateStore </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreMakeRequest</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    response </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">liftAff </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> AX</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">get </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">AXRF</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://api.github.com/users/"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    updateStore </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreReceiveResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (map _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body (hush response))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  ReceiveState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">put </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveState input</span></span></code>

The really nice things about this approach are:

  • components could be self-sufficient, as opposed to Elm:
    • they can have both internal state and communicate with the external application via Aff
    • they can be extracted into separate modules, making them actually reusable components
  • state selectors and connecting to a store are seamlessly implemented based on existing Halogen tools (subscriptions)
  • it feels like you do not have to worry about state growing big, since each component explicitly declares which parts of that messy furball it needs (derives)

The bad news is that everything relies on monads and transformers - lifting, mapping, flat-mapping are just the very tip of the iceberg. Once you hit some mysterious error - it is quite tricky to understand what is going on. Unlike Elm, which has really nicely structured, formatted and presented both error message, its location and ways to fix it.

Just looking at the type definitions is nauseaing at best:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handleAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> output m</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadAff</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MonadStore</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StoreAction</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> H.HalogenM</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> State</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> () output m </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Unit</span></span></code>

And then there is this bit, lifting everything to the same monad and then mapping and flat-mapping it to get the response body:

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">MakeRequest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">liftEffect </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Event</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">preventDefault event</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  username </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gets _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">username</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  updateStore </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreMakeRequest</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  response </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">liftAff </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> AX</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">get </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">AXRF</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://api.github.com/users/"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  updateStore </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> StoreReceiveResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (map _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body (hush response))</span></span></code>

And do not forget that this monad is merely describing the computation, you will have to run it at some point:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runHalogenAff </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HA</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">awaitBody</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  root </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runStoreT initialStore reduce component</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ui </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runUI root unit body</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ui</span></span></code>

The example on halogen-store suggests using launchAff_ , but then you will have to cast the return value type to match the monad of the main function ( Effect Unit ) or lift runStoreT to the Effect Unit monad - whichever you find suitable:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> launchAff_ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HA</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">awaitBody</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  root </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runStoreT initialStore reduce component</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ui </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> runUI root unit body</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  void ui</span></span></code>

But having to worry about all these intricacies actually strengthens the point that PureScript is not for the faint-harted - Elm prevails here.

The other drawback is that mixing logic in both component and the reducers is weird - it is not clear from the Flux architecture where the side-effects should live - like network calls, asynchronous actions, actions triggering other actions. Redux is known for suffering from all of these areas.

Elm solves this nicely with commands.

Halogen kind of takes a step backwards from Elm - it does have subscriptions, but it does not prevent you from issuing side effects from the handleActions . And halogen-store does not have a recipe for complex chained actions.

Ultimately, I don't think Redux is bad - the idea to have a full visibility into all possible application interactions is scary in a complex project and it is hard to come up with a clean way to work around it, but single-way data flow is actually nice.

Interesting how developers went from "we don't want Angular.js dirty checks - it is not clear where the data is flowing" to "we don't want a single point of contention for all application interactions" .

In my eyes, the four technologies (modern-day React, Redux, Elm and Purescript) all come with their own pros and massive cons and there is no good or one-size-fits-all solution among them. And none of them ultimately solves the problem of managing application state and interactions in a non-bloated way. Maybe Angular or React 19 have an answer?

Bun is still undercooked urn:uuid:aeac46fd-79e0-5691-9f78-8e9694cf7343 2024-05-17T00:00:00Z 2024-05-17T00:00:00Z Bun is still undercooked Artem Shubovych

my Skunkworks project was trying out Bun . it was not a successful project, but there are some learnings:

TL;DR: I think Bun is still undercooked and despite being super cool and competitive on paper, it is a bit too early to use it in big projects. But hey, it works for my blog!

What is Bun

Bun is a combined alternative for NodeJS, package manager ( npm / yarn / pnpm ), bundler ( vite / webpack / esbuild ) and test runner ( vite / jest ).

Bun is ridiculously fast

Command Yarn Bun
yarn install 49 sec 7.5 sec
vite build 14 sec 0.9 sec
vite test forever 4.5 sec

This most likely has to do with what happens in those tools - Bun went with parsing files as ASTs, applying transformations and running them in memory (to the best of my knowledge, digging through the Bun code)

Some things work out of the box

Dependency management works like a charm. No questions asked. Bun is just 7x faster. Comparing the node_modules directories:

<code>Only in node_modules_yarn:
    .yarn-state.yml
    @aashutoshrathi
    @isaacs
    @npmcli
    @pkgjs
    @tootallnate
    abbrev
    agentkeepalive
    aggregate-error
    aproba
    are-we-there-yet
    asynciterator.prototype
    cacache
    chownr
    clean-stack
    color-support
    console-control-strings
    deep-equal
    delegates
    depd
    eastasianwidth
    encoding
    env-paths
    err-code
    es-get-iterator
    exponential-backoff
    foreground-child
    fs-minipass
    gauge
    graceful-fs
    has
    has-unicode
    humanize-ms
    ip
    is-lambda
    jackspeak
    jsonc-parser
    make-fetch-happen
    minipass-collect
    minipass-fetch
    minipass-flush
    minipass-pipeline
    minipass-sized
    minizlib
    mkdirp
    negotiator
    node-gyp
    nopt
    npmlog
    object-is
    p-map
    promise-retry
    retry
    set-blocking
    smart-buffer
    socks
    socks-proxy-agent
    ssri
    stop-iteration-iterator
    string-width-cjs
    strip-ansi-cjs
    tar
    unique-filename
    unique-slug
    wide-align
    wrap-ansi-cjs

Only in node_modules_bun:
    confbox
    es-object-atoms
    word-wrap
</code>

Curious to see if those packages missing in bun's node_modules are actually used anywhere.

Plugins

In Relational Migrator we use few plugins with vite, namely svgr , vanilla-extract and sentry . Bun only supports limited esbuild plugins and does not have the aforementioned plugins. Some of them work with minimal changes, some of them do not work entirely.

svgr plugin

svgr worked with minimal alterations:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgrEsbuildPlugin </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'esbuild-plugin-svgr'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Bun</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">build</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    plugins</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        svgrEsbuildPlugin</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> unknown</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BunPlugin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

But required to change the imports from

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReactComponent </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DatabaseAccessImage </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> './assets/database-access-image.svg'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

to

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DatabaseAccessImage </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> './assets/database-access-image.svg'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

vanilla-extract plugin

This one loads vite server to compile the CSS and does not work no matter what I tried, throwing the following errors all over the place:

<code>error: Styles were unable to be assigned to a file. This is generally caused by one of the following:

- You may have created styles outside of a '.css.ts' context
- You may have incorrect configuration. See https://vanilla-extract.style/documentation/getting-started
      at getFileScope (.../frontend/node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.cjs.dev.js:35:11)
      at generateIdentifier (.../frontend/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.cjs.dev.js:175:7)
      at style (.../frontend/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.cjs.dev.js:374:19)
      at .../frontend/src/shared/leafygreen-ui/badge/badge.css.ts:4:28
</code>

Followed by

<code>error: Module._load is not a function. (In 'Module._load(file, parentModule)', 'Module._load' is undefined)
    at .../frontend/src/components/mapping-banner.css.ts:1:0
</code>

sentry plugin

This one was trivial and did not complain (I did not check if it actually works):

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Bun</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">build</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    plugins</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        sentryEsbuildPlugin</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                disable</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">env</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">SENTRY_AUTH_TOKEN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                org</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'mongodb-org'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                project</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'relational-migrator-frontend'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                telemetry</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                sourcemaps</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        filesToDeleteAfterUpload</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '**/*.map'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> unknown</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BunPlugin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Bundling

Bun is great to run bundling, testing or manage packages from CLI when things are relatively simple. When you need plugins (for instance), the interactions become tricky. For specifying and configuring bundle-time plugins one needs to use Bun's JS/TS API and make a custom build script:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">await</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Bun</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">build</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

By default, Bun does not log anything, which is actually quite inconvenient - not even build failures are logged. One has to get the result of Bun.build() and manually process them, which is a bit of a bummer:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> await</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Bun</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">build</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">success) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Build failed'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> message </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">logs) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(message)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">info</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Build succeeded'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Configuration

Another inconvenient interaction - some actions require entire scripts (like build configuration, serving files, etc.). Then there is a config file, bunfig.toml where users can specify some configurations for Bun.

Running tests

This one had the most issues on my end.

react-testing-library

Bun declares support for react-testing-library , which worked as expected.

Browser APIs

Had to use happy-dom and configure it in the bunfig.toml to enable some of the UI testing features (such as access to the window object). Yet, happy-dom still lacks support for Canvas API , for instance.

test.each

It is one example of Bun's partial compatibility with Jest - with Jest one can use nice-ish string interpolation to generate test name:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    currentStep | lastCompletedStep | progressType</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ${</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">        | </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">              | </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#40A02B;--shiki-dark:#A6D189">'active'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ${</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">        | </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">              | </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#40A02B;--shiki-dark:#A6D189">'inactive'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ${</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">        | </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">              | </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#40A02B;--shiki-dark:#A6D189">'checked'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">  `</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'returns $progressType for $currentStep and $lastCompletedStep'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> currentStep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> lastCompletedStep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> progressType</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

With bun:test it is slightly different - you can't use arguments out of order, nor do you have access to their names. Neither can you use this nice syntactic sugar for defining test cases in a table manner.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cases </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // currentStep | lastCompletedStep | progressType</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'active'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'inactive'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'checked'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(cases)(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'For %p and %p returns %p'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">currentStep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> lastCompletedStep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> progressType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getProgressType</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(currentStep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lastCompletedStep))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toEqual</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        progressType</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Oh, and there is no describe.each() functionality at all, which makes defining suites of tests more tedious.

Mocks

Mocks work as expected, out of the box. There are mocks for system clock, which is nice. Had to replace vi.fn() with mock() and a corresponding import { mock } from 'bun:test'; .

ObjectContaining matchers

When using nested matchers in the ObjectContaining , some of them are missing in Jest compatibility (like expect.toBeNumber ):

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(nodes)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toEqual</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        expect</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">objectContaining</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'node-1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          position</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> expect</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toBeNumber</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> expect</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toBeNumber</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Had to use expect.any(Number) instead:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(nodes)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toEqual</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        expect</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">objectContaining</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'node-1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          position</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> expect</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Number)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> expect</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Number) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Using Fragment import alongside &#x3C;>

If a component contains both import { Fragment } from 'react' and uses a shorthand &#x3C;> , Bun will yell at test time (but not at build time, interestingly enough):

<code>SyntaxError: Cannot declare an imported binding name twice: 'Fragment'.
</code>

If you specify a different jsxFragmentFactory in tsconfig.json and set "jsx": "react" (and not "react-jsx" or anything), you will get further.

After meddling with Bun source code itself, I figured something (like it parses files' AST and modifies them to add missing imports, like Fragment but it ends up with duplicates), but even after applying some crude hacks to prevent it from adding those duplicate statements, I could not get to fix the issues. Left a comment on Bun's Github issue , but from my experience developers do not pay enough attention to those.

Ended up manually changing sources for the libraries in question in node_modules folder directly (just for the test), which did actually help. Might be worth changing it in the libraries directly, but that won't work with everything.

Ace editor

It still is kinda impossible to use UMD/AMD modules in conjunction with TS in Bun tests - the nature of UMD is that once the file is imported, it uses IIF to define stuff, but Bun does not tolerate this (I presume it only parses the AST of the imported file but does not actually execute it in the right order).

Hence Ace editor, which uses UMDs, can not really be used as intended.

Bun's meat and potatoes

I did a bit of digging in Bun's source code and it seems... immature - commented out code, ignored tests, thousand-line-functions and files ( js_parser.zig has 23.3k LOC ). And this is on top of using Zig, which is still at version 0.12 (as of writing of this post, 10 May 2024 ) and has quite limited standard library (no remove and find methods in lists, no hash sets, etc.).

Bottom line

My experience shows that Bun might fine to be used in new and low-risk projects, but it is not ready for a drop-in replacement in existing or more or less complex projects.

Strongly-typed front-end: experiment 2, simple application, in PureScript / Halogen urn:uuid:4ecf449c-fcb8-51e1-9d72-47f03c0ebe81 2024-05-17T00:00:00Z 2024-05-17T00:00:00Z Strongly-typed front-end: experiment 2, simple application, in PureScript / Halogen Artem Shubovych

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

A more "conventional" way to implement the front-end application in PureScript would be using a framework called Halogen .

Starting off with a "hello world" example:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> H</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.Aff </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HA</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Events </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.VDom.Driver (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runUI</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HA</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">runHalogenAff </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HA</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">awaitBody</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  runUI component unit body</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Increment</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Decrement</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">component </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkComponent</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    { initialState</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eval</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkEval </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">defaultEval { handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handleAction }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  initialState _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  render state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onClick </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Decrement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"-"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show state ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      ,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onClick </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Increment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"+"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Increment</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Decrement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span></code>

Adding the utility code akin to the other technologies:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getShape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span></code>

This resurfaces few differences from Haskell, Elm and others:

  • there is no pi constant in the Prelude , so need to import one of the available definitions , I went with Data.Number
  • Float is not a type; there is Number , however
  • 0 is not a Number , it is Int , confusing the audience

These are all minor differences, however. But this code is not a conventional PureScript either - it is working against the good practices of functional programming and thus defeats the purpose of these experiments. Examples of this are the heavy reliance on String instead of using the available type system.

Let us change that a bit:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.String.Read (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Read</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Read</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  read </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "square"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "circle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Show</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  show </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Square</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "square"</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Circle</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "circle"</span></span></code>

Now, to the UI:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Properties </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HP</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">render state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"&#x3C;area>"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span></code>

In the application state we need to store the selected shape and the value, so we can utilize records for that:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">initialState _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span></code>

Then we need to modify the possible actions. Let's stick to the same approach of utilizing the type system:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

The thing glueing the two together is the handleAction function:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  ChangeValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state { value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value }</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  ChangeShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state { shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape }</span></span></code>

Here, unlike Haskell (to my best knowledge), the placeholder variable is being used for pattern matching against the only function argument. So instead of a little verbose

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handleAction action </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  -- ...</span></span></code>

you can use this placeholder variable and just provide the branches for each of its possible values:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  -- ...</span></span></code>

Modifying the state is done using the Halogen.Hooks.HookM.modify_ function, which allows us to only use the previous state value and provide a new state value, without the need to mess with monads. In turn, we modify the state record using the record syntax:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state { shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newShapeValue }</span></span></code>

Now the only bit left is tying the UI with the actions:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Events </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.String.Read (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">read</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Number </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Tuple (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Tuple</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">render state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChange onShapeChanged ] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChange onValueChanged ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_ [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"&#x3C;area>"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (read v)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChanged v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">N</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromString v)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">showArea state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Nothing</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Choose shape and provide its parameter"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Tuple</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape area) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Area of "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show shape) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " is "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show area)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      pure (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Tuple</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape area)</span></span></code>

Here is where most fun and benefit from using PureScript comes into play.

First of all, the HE.onValueChange event handler (the onShapeChanged and onValueChanged functions) - it will be called with the new value for the input instead of an entire event object. This allows us to skip unpacking the raw value from that object.

Then, the action dispatchers take the value from the input and try to parse it, returning a Maybe a :

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onShapeChanged</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (read v)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onValueChanged</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChanged v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">N</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromString v)</span></span></code>

It is actually a quite important part, since the shape might not be selected (making the &#x3C;select> value an empty string) and the value might be either a blank string or not a valid number string. PureScript does not allow us to not handle these cases, so whenever we parse the user input, we get a Maybe a value and we have to handle both scenarios when the value is valid and when it is not.

The function showArea is where this neatness comes together - we handle both values as one, using the Data.Tuple type to pair them together:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- unpacks `Shape` from `Maybe Shape`</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- unpacks `Number` from `Maybe Number`</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape value </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- always returns a Number, since both `shape` and `value` are always provided</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  pure (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Tuple</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape area) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- returns a tuple of shape and area, packed in a `Maybe`</span></span></code>

The above code will shortcircuit whenever at any point it is trying to unpack a value from a Nothing and the whole do block will return Nothing .

Putting it all together:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Number </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.String.Read (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Read</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> read</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Tuple (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Tuple</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> H</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.Aff </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HA</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Events </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.HTML.Properties </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HP</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Halogen.VDom.Driver (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runUI</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> N</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Read</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  read </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "square"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "circle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Show</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  show </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Square</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "square"</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Circle</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "circle"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Action</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">component </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkComponent</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    { initialState</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eval</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mkEval </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">defaultEval { handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handleAction }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  initialState _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  render state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChange onShapeChanged ] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HP</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (show </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">HE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChange onValueChanged ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div_ [ showArea state ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  onShapeChanged v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (read v)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  onValueChanged v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ChangeValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">N</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromString v)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  showArea state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      Nothing</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape and provide its value"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Tuple</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape area) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        HH</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Area of "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show shape) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " is "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show area)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pure (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Tuple</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape area)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  handleAction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    ChangeValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state { value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value }</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    ChangeShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      H</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modify_ </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state { shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HA</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">runHalogenAff </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  body </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> HA</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">awaitBody</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  runUI component unit body</span></span></code>
More than TypeScript urn:uuid:ccbaea3d-3448-56ae-87aa-627c84e27a39 2024-05-12T00:00:00Z 2024-05-12T00:00:00Z More than TypeScript Artem Shubovych

Back in 2011 frontend was a very different thing - JavaScript had no class , Object.entries / Object.keys , promises were a proof of concept idea (unless you used 3rd party library bluebird ) and Node was v0.10.

Then came CoffeeScript , which added nice helper features to JavaScript - list comprehensions, classes, string interpolation and if statements (meaning you could use them for variable assignment):

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># if statements</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> happy </span><span style="color:#179299;--shiki-dark:#81C8BE">and</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> knowsIt</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  chaChaCha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sexy</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  knowsIt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tooSexy</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  removeShirt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  showIt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># list comprehensions</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">courses </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'greens'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'caviar'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'truffles'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'roast'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'cake'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">menu</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dish</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Menu Item </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dish</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">menu</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dish </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dish</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> courses</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># ranges and list comprehensions</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">countdown </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (num </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> num </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#179299;--shiki-dark:#81C8BE">..</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># iterating over object entries</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">yearsOld </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> max</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ida</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tim</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ages </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> age </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> yearsOld</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">  "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> is </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">age</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span></code>

Whilst it was still compiled to an inferior ES5 JavaScript, it helped to organise the code and make it substantially cleaner. The one drawback is that it did not provide any type safety (only added recently, via @flow and you would still have to duplicate your classes if you wanted to use it - once in coffeescript and once in @flow annotations) . Anyhow, CoffeeScript was a good tool for the task, if you ask me.

Then came Dart , Flow and TypeScript, which were also compiled to ES5 JavaScript, but instead of adding new syntax features, they aimed to solve a different problem - by introducing types they sought to reduce the number of runtime errors with type checks at compile time.

This sounded so good that many developers and companies immediately got on board. Alas, the new tech still suffered from the same issue as JavaScript itself and most common cause of runtime errors - the null and undefined still was a thing, causing the exact same runtime errors.

The one true benefit offered by TypeScript over the others was that it allowed to seamlessly use existing JavaScript code. And, provided you have the type signatures for that JavaScript code, it could even perform type checking on it too, effectively reducing the requirements for using TypeScript in the existing codebase. No wonder it was an easy buy-in for many projects.

Fast-forward to 2024 ( twelve years since its first release) and TypeScript dominates the frontend world. Over the years it seems to have been focused on improving the type system in terms of what can you do with types - union types, partial types, etc. It still suffers from the original issues though and there still are not too many new syntactic features to pair with its powerful type system (like pattern matching).

With the new EcmaScript standards, classes and promises becoming the first-class citizens in all browsers (even Internet Explorer / Edge, when it was still around), the APIs and syntax became more mature ( Object.entries , async / await to reduce callback hell , for .. of , const / let , string interpolation and many others). There are still no list comprehensions or conditional expressions / pattern matching though.

TypeScript still does help in what I think is a small subset of highly-specific scenarios like navigating the code (jump to definition / declaration / find usages) in the IDE and refactoring the code. But IDEs matured as well, code navigation is not as much of a feature unique to TypeScript anymore as it used to be (in the era of Sublime Text). TypeScript can prevent some really naive errors at compile time like using a number instead of an object, but I don't think developers run into them these days - because, again, IDEs are really powerful these days, even VSCode and they help eliminate such mistakes to a large degree.

Let's consider a real-world scenario (from my work project): server returns a list of LocationType objects. Each one of the objects can be either a Collection , a Document (in a specific collection) or a Table , each with its own subset of fields, specific to the type. We need to handle each case differently (display them on the UI differently).

The OpenAPI spec:

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">tableLocation</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> object</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  required</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    -</span><span style="color:#40A02B;--shiki-dark:#A6D189"> table</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  properties</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    table</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> string</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">collectionLocation</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> object</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  required</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    -</span><span style="color:#40A02B;--shiki-dark:#A6D189"> collection</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  properties</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> string</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">documentLocation</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> object</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  required</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    -</span><span style="color:#40A02B;--shiki-dark:#A6D189"> collection</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    -</span><span style="color:#40A02B;--shiki-dark:#A6D189"> document</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  properties</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> string</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    document</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> string</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">location</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  oneOf</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    -</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> $ref</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "#/components/tableLocation"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    -</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> $ref</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "#/components/collectionLocation"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    -</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> $ref</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "#/components/documentLocation"</span></span></code>

And the TypeScript code generated by OpenAPI for the above spec looks like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    document</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    table</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> instanceOfCollectionLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "collection"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> instanceOfDocumentLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "collection"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "document"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> instanceOfTableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "table"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInstance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CollectionLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ignoreDiscriminator</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'collection'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'collection'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DocumentLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ignoreDiscriminator</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'collection'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'collection'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'document'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'document'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> TableLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ignoreDiscriminator</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'table'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'table'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> JobLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ignoreDiscriminator</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">CollectionLocationFromJSONTyped</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">DocumentLocationFromJSONTyped</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TableLocationFromJSONTyped</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This might be a bit too harsh on TypeScript as a language, considering this is not the best implementation (in my opinion), but this highlights one of the issues with TypeScript: this very same code caused a number of runtime errors caught by users - not exceptions, not compilation errors, but wrong UI behaviour - on the UI all locations were treated as a table location.

The reason why this was happening is the code itself - it does not really handle the choice type JobUpdateLocation correctly and instead of a choice type it returns a union type, to put it roughly - instead of oneOf it returns essentially allOf object.

Now, even if we were to rewrite it by hand (which would defeat the purpose of using OpenAPI and could be harder to keep in sync between client and server code), we would end up with something like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic">    collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic">    collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic">    document</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic">    table</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> instanceOfCollectionLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"collection"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"document"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> instanceOfDocumentLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"collection"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"document"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> instanceOfTableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> boolean</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"table"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CollectionLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'collection'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'collection'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DocumentLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'collection'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'collection'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'document'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'document'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> TableLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'table'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'table'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> JobLocationFromJSONTyped</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">json</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (json </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfCollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfDocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfTableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CollectionLocationFromJSONTyped</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfDocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfCollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfTableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DocumentLocationFromJSONTyped</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfTableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfCollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instanceOfDocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> TableLocationFromJSONTyped</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(json)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This is quite a verbose code, with few bad practices in place (the use of any and object , need to always be conscious of undefined ), but this is literally what we ended up doing (the helpers, not redefining the types).

The types in TypeScript (or rather classes and interfaces) are also a point of a few confusing tricks you have to keep in mind - if we were to use class instead of type , as follows

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> table</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

we would eventually run into the similar bug at runtime, which is a perfectly valid behaviour from the perspective of TypeScript, because of type compatibility , meaning DocumentLocation and CollectionLocation could be used interchangeably, since they have a subset of compatible fields:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'col'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'doc'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'col'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // also ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // not ok</span></span></code>

This would not work if CollectionLocation , DocumentLocation and TableLocation were types instead:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'col'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'doc'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // not ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'col'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // not ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // not ok</span></span></code>

And the code to parse location from JSON is actually quite ugly. It would benefit so much from switch expressions or pattern matching !

And we still have to remember to handle those potentially undefined values whenever we use the helper functions. And here's an example from literally few days ago:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Job</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    projectId</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jobsInProgress</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Job[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> message </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useProjectStatus</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    jobsInProgress[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectId </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useProjectStatus</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">projectId</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    const </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">useQuery</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queryFn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> () </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`/project/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return data;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

The above code started throwing an error, since server responded with 500 Server Error . Reason was quite simple - the projectId , which we recently started to validate on the server (expecting it to be a valid ID), was a blank string. Interesting thing: no one has questioned the very line causing the "default value" for projectId to become an empty string:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">jobsInProgress[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectId </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span></code>

And issues like these are unbelievably common in front-end world, while being quite tricky to detect and resolve. To fix this particular issue we added a client-side validation (to an extent) to run the query only when the projectId value is provided:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">useQuery</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  enabled</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#179299;--shiki-dark:#81C8BE"> !!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  queryFn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`/project/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

The problem remains: it is really easy to miss this rather small fallback to an empty string.

There is a solution in Scala world that somewhat addresses this issue - refined types , which allows to have something along the lines of:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eu</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timepit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">refined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eu</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timepit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">refined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">api</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Refined</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eu</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timepit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">refined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NonBlankString</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MatchesRegex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">".+"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useProjectStatus</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">projectId</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Refined</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NonBlankString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> ???</span></span></code>

This would require wrapping all the values passed to fetchData in refineV[NonBlankString]() call and handling the case when the validation fails:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> generateId</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"some"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">).last</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Refined</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NonBlankString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> println(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">s</span><span style="color:#40A02B;--shiki-dark:#A6D189">"fetching '</span><span style="color:#7C7F93;--shiki-dark:#949CBB">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#40A02B;--shiki-dark:#A6D189">'..."</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">args</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]) </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> refineV[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">NonBlankString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">](generateId())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> yield</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fetchData(id)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

But in the land of TypeScript, there is only so much you can do - TypeScript only works at compile time.

The above examples might sound like very far-fetched edge case scenarios, but keep in mind: this is the code generated automatically by one of the most popular tools from a trivial schema. This is not as far-fetched as it might seem.

Can we do better in TypeScript? Something like refined in Scala? What if we had a powerful type system and syntax to support it? And, if possible, get rid of the null and undefined along the way?

The problem of null and undefined can be mitigated to an extent by using some concepts of functional programming, similarly to how I showcased some time ago . It would be quite hard to achieve, though, given the problem remains imbued in the language itself. Moreover, targeting the issues described above, it would take an entire standard library to really reduce the possibility of the issue:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jobInProgressMaybe</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Job</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Job</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(jobsInProgress)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">first</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projectIdMaybe</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jobInProgress</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">j</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectId)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">useQuery</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  enabled</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projectIdMaybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isSome</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  queryFn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    projectIdMaybe</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatMap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">projectId</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`/project/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">orElse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Promise</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'no projectId'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

We could try to address the empty string issue with the extensive type system:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NonEmptyString</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">T </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> T </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> never</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyString</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">T </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchData</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">T </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NonEmptyString</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">T</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`Fetching </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

But it would only work if all the values are known at compile time, which is easily broken with the simplest test:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> generateId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NonEmptyString</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'moo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NonEmptyString</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">''</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // not ok</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">generateId</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ok, but guaranteed undefined behaviour at runtime</span></span></code>

And it would take even more effort to make all types uniquely identifiable (to solve the choice type problem).

The way most developers would approach solving similar issues in a real-world project would be (at best) adding some linters, checkers and relying on automated tests and high-quality code reviews. In my experience, this is a rather flimsy excuse rather than a real solution and it does not work most of the time - especially in edge case scenarios.

This is where I'd suggest to use another language altogether, which, similarly to CoffeeScript and TypeScript back in the day, solved some problems at compile time. And suggest I will.

There is a big warning before I proceed though: another technology is a rather big decision, not to be taken lightly. Some might see it as an impossible switch, only few small or indie developers on rather unimportant projects would make. But remember it was the same story with ES6, TypeScript, bundlers and pretty much any significant upgrade in the past.

Balance bike is a good tool to get you going - it gets you from walking to moving fast. But if you want to get faster and further, you have to drop it at some stage in favour of a more advanced bike.

Similarly to how TypeScript and ESNext got you from plain callback-hell-infested JavaScript code to a better place - you can refactor code faster, it saves you from a few errors at compile time, the code is much cleaner and conscise now. But if you really want to get even further, you will have to make a leap of faith, make an investment into the future.

Here is my big controversial suggestion: a pure functional language, one with strong type system, which does not have a concept of null and undefined in the first place, with a nice sweet syntax.

Before landing on a specific choice, check out Elm (dead, but a good starting point) and PureScript, in that order. Let me explain.

Elm is like a very simplified Haskell - it is a pure functional language with a subset of Haskell syntax. It has a nice compiler with really good error messages. It enforces a structure for your application (redux-like). It gives you a gentle introduction to the functional programming concepts and it targets browsers (web applications). With its architecture, you can look at the message (action from redux) type and see exactly what are all possible operations in the application (which makes reading code and getting to know new codebases much easier).

On a bad note, it is not being developed since 2019, it comes with an entire runtime (saves you from runtime errors, but blows up the bundle size) and it is a all-or-nothing commitment for the project - it is an all-in-one platform and if you want to gradually update your application from React - sorry, you will have to rewrite entire parts of you application entirely in Elm. The good point turned bad, having all possible actions defined in one message type make complex applications really complex (with one massive type definition, an issue very familiar to developers who had to deal with Redux).

here could have been an Elm code sample

The next step on this journey would be PureScript. It is an actively developed language, it has a minimal footprint after compiled to JS (much smaller than Elm), it has a very rich ecosystem and, best of all, it has a very simple interop with JS and it can compile just one module. Top it up with Halogen framework and you effectively got yourself Elm on steroids. The downside is that it is slightly more complex platform (language and framework) compared to Elm, so the learning curve is a bit steeper.

The above example of CoffeeScript code could be written in plain PureScript like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> happy</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Boolean</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> knowsIt</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Boolean</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sexy</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Boolean</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> tooSexy</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Boolean</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> chaChaCha</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> knowsItStr</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> removeShirt</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> showIt</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Array (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mapWithIndex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Map </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> M</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Tuple (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Tuple</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- if statements with multiple branches become pattern matching</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> happy </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> knowsIt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> chaChaCha</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sexy </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> knowsItStr</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tooSexy </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> removeShirt</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> showIt</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- list comprehensions become function application</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">courses </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">"greens"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "caviar"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "truffles"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "roast"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "cake"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- string interpolation is possible via an external packages</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- https://pursuit.purescript.org/packages/purescript-interpolate</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Interpolate </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> I</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">menu' i dish </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> I</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Menu Item "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#40A02B;--shiki-dark:#A6D189">": "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dish</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- https://pursuit.purescript.org/packages/purescript-template-strings</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.TemplateString.Unsafe (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(&#x3C;~>)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">menu'</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i dish </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Menu Item ${i}: ${dish}"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;~></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { i</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dish</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dish }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.TemplateString (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(&#x3C;->)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Tuple.Nested (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(/\)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">menu'</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i dish </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Menu Item ${i}: ${dish}"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> &#x3C;-</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">"i"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "dish"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dish ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- pure PureScript string interpolation</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">menu i dish </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Menu Item "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show i) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#40A02B;--shiki-dark:#A6D189"> ": "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dish</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x i dish </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> menu (i </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) dish</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- can not just call a function and ignore its result</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x' </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mapWithIndex x courses</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- ranges become Array monad</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- countdown :: Array Int</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">countdown </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  num </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#179299;--shiki-dark:#81C8BE"> ..</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  pure num</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- JavaScript objects exist in a separate package</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Foreign.Object </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FO</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">yearsOld' </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> FO</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromHomogeneous { max</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ida</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tim</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- object as Map</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">yearsOld </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> M</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromFoldable [</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Tuple</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "max"</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Tuple</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "ida"</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Tuple</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "tim"</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y child age </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show child) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " is "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show age)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ages </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> map y yearsOld</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ages </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> map y yearsOld'</span></span></code>

The real deal with this approach is how to migrate from an existing (most likely) React/TypeScript/(webpack | vite) ecosystem to PureScript?

Expanding on Scott Wlaschin's talk, you can (and probably should) separate the pure application logic from IO, potentially utilising the foreign imported functions to interact with the existing JS code (libraries). This way you keep your application logic error-free, and all the errors that can happen are shifted towards the presentation layer (MVC/MVP, remember this concept?).

This would be the best strategy for the most projects, migrating one bit at a time and making the application less and less error prone whilst not wreaking the havok by rewriting everything from scratch (very few businesses will buy into that).

The bigger issue is that most modern frontend apps I have seen are so mangled in mixing the business logic and the presentation layer, it would be challenging (to say the least) to unmangle it back to a reasonable code. Check how we handle UI action, triggering a HTTP request and updating both the UI (to display the request progress/status) and the application state (for other parts of the UI) at the same time.

here could have been a real-world application interaction handling code sample

Calling PureScript code from JavaScript (based on FFI example in PureScript book ):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Test </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">gcd</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gcd </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gcd n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gcd n m</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m     </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gcd (n </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m) m</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gcd (m </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n) n</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ZeroOrOne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Zero</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> One</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ZeroOrOne</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ZeroOrOne</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">inc </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Zero</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Zero</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">inc (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">One</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n) </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> One</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (n </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_zero </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Zero</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_one </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> One</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_two </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> One</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span></code>

and then in JS:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Test </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Test.js'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">gcd</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _zero </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Zero</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _one </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">One</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _two </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">One</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(_zero))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(_one))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Test</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(_two))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

In the other direction (calling JS code from PureScript):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setItem</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> key</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  window</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">localStorage</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setItem</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getItem</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> key</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  window</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">localStorage</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getItem</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(key)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

and then in PureScript:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setItem</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreign</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> import</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getItem</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Json</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Argonaut (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DecodeJson</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> EncodeJson</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Argonaut.Decode.Generic (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">genericDecodeJson</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Argonaut.Encode.Generic (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">genericEncodeJson</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Generic.Rep (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Generic</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- define PhoneType</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">derive instance</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Generic</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PhoneType</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> EncodeJson</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PhoneType</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> encodeJson </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> genericEncodeJson</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DecodeJson</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PhoneType</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decodeJson </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> genericDecodeJson</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">processItem</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Json</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Person</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">processItem item </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  jsonString </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decodeJson item</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  j          </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jsonParser jsonString</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  decodeJson j</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  item </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getItem </span><span style="color:#40A02B;--shiki-dark:#A6D189">"person"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  initialPerson </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> processItem item </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  err </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      log </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Error: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> err </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#40A02B;--shiki-dark:#A6D189"> ". Loading examplePerson"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      pure examplePerson</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    Right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p   </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pure p</span></span></code>

To align this with the original problem about JobLocation , here's how this would look like in PureScript:

<code class="language-purs">module Main where

import Prelude
import Data.Argonaut (jsonParser)
import Data.Argonaut.Decode (decodeJson, (.:), printJsonDecodeError)
import Data.Argonaut.Decode.Class (class DecodeJson)  
import Data.Argonaut.Decode.Error (JsonDecodeError(..))
import Data.Argonaut.Encode (encodeJson, (:=), (~>))
import Data.Argonaut.Encode.Class (class EncodeJson)
import Data.Bifunctor (bimap)
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
import Data.Show.Generic (genericShow)
import Effect (Effect)
import Effect.Console (log)

data JobLocation
  = CollectionLocation { collection :: String }
  | DocumentLocation { collection :: String, document :: String }
  | TableLocation { table :: String }

derive instance Eq JobLocation
derive instance Generic JobLocation _
instance showJobLocation :: Show JobLocation where
  show a = genericShow a

instance DecodeJson JobLocation where
  decodeJson json = do
    obj &#x3C;- decodeJson json
    
    -- Check which fields are present
    maybeCollection :: Maybe String &#x3C;- obj .:? "collection"
    maybeDocument :: Maybe String &#x3C;- obj .:? "document" 
    maybeTable :: Maybe String &#x3C;- obj .:? "table"
    
    let hasCollection = isJust maybeCollection
    let hasDocument = isJust maybeDocument
    let hasTable = isJust maybeTable
    
    case hasCollection, hasDocument, hasTable of
      true, true, false -> do
        collection &#x3C;- obj .: "collection"
        document &#x3C;- obj .: "document"
        pure $ DocumentLocation { collection, document }
        
      true, false, false -> do
        collection &#x3C;- obj .: "collection"
        pure $ CollectionLocation { collection }
        
      false, false, true -> do
        table &#x3C;- obj .: "table"
        pure $ TableLocation { table }
        
      _, _, _ -> Left $ AtKey "structure" $ UnexpectedValue json

parseJobLocation :: String -> Either String JobLocation
parseJobLocation jsonStr = jsonParser jsonStr >>= (decodeJson >>> bimap printJsonDecodeError identity)

-- Example usage
examples :: Effect Unit
examples = do
  let collectionJson = """{"collection": "users"}"""
  case parseJobLocation collectionJson of
    Left err -> log $ "Collection parse error: " &#x3C;> err
    Right location -> do
      log $ "Parsed CollectionLocation: " &#x3C;> show location
  
  let documentJson = """{"collection": "users", "document": "user123"}"""
  case parseJobLocation documentJson of
    Left err -> log $ "Document parse error: " &#x3C;> err
    Right location -> do
      log $ "Parsed DocumentLocation: " &#x3C;> show location
  
  let tableJson = """{"table": "analytics"}"""
  case parseJobLocation tableJson of
    Left err -> log $ "Table parse error: " &#x3C;> err
    Right location -> do
      log $ "Parsed TableLocation: " &#x3C;> show location
  
  let invalidJson = """{"data": "something"}"""
  case parseJobLocation invalidJson of
    Left err -> log $ "Expected error: " &#x3C;> err
    Right location -> log $ "Unexpected success: " &#x3C;> show location

main :: Effect Unit
main = do
  examples
</code>

While this code is type safe and will handle all of the edge cases just perfectly, I find it pretty hard to read. Parts that I would be unable to understand in a month of not working with this code, like this one:

<code class="language-purs">parseJobLocation jsonStr = jsonParser jsonStr >>= (decodeJson >>> bimap printJsonDecodeError identity)
</code>

It could be rewritten in an imperative way:

<code class="language-purs">parseJobLocation jsonStr = do
  json &#x3C;- jsonParser jsonStr
  bimap printJsonDecodeError identity (decodeJson json)
</code>

But I doubt this makes it any more readable - the bimap printJsonDecodeError identity (decodeJson json) part, specifically. This is a common issue with Haskell and PureScript - some of the functions are weirdly named and can only be understood either with experience or by reading the docs (which, in turn, are also quite cryptic). Take the bimap function for example. Its signature looks like this:

<code class="language-purs">bimap :: forall a b c d. (a -> b) -> (c -> d) -> f a c -> f b d
</code>

This does not really help non-seasoned Haskeller.

The docs only say this:

The bimap function maps a pair of functions over the two type arguments of the bifunctor.

I had to use it since there are two function calls in parseJobLocation : jsonParser :: String -> Either String Json and decodeJson :: Json -> Either JsonDecodeError a . This means if you just pipe the output of the first to the second ( jsonParser jsonStr >>= decodeJson ), the return type should match - because of the nature of the >>= operator: >>= :: (b -> c) -> m a b -> m a c , meaning for Either a b and a function b -> c the return type would have to be Either a c , in our case (Json -> a) -> (Either String Json) should return Either String a , but decodeJson returns Either JsonDecodeError a instead. Effectively, >>= operates on the second argument of a functor (in case of Either a b , operator >>= changes b ), whereas we want to change it first and then change the first argument as well (making the chain Either String Json -> Either JsonDecodeError a -> Either String a ). But this has to be done in one go - or, rather, in one argument of >>= . We can create such function by combining decodeJson which returns Either JsonDecodeError a and another function, which converts that middle argument, JsonDecodeError into String , making it Either String a . We achieve this by using the >>> operator which is an alias for composeFlipped and is defined as composeFlipped :: a b c -> a c d -> a b d . In fact, instead of using bimap _ identity _ it is better to use lmap _ _ which would only apply function to the left side of Either :

<code class="language-purs">parseJobLocation jsonStr = do
  json &#x3C;- jsonParser jsonStr
  lmap printJsonDecodeError (decodeJson json)
</code>

Explanations like those make it a huge barrier to entry for newcomers.

Incorporating the above solution in an existing TypeScript project might look a tad cumbersome. For Vite, there is a PureScript plugin:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> defineConfig </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'vite'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> purescript </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'vite-plugin-purescript'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> default</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> defineConfig</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  plugins</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    purescript</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The tricky part is that we have to re-define types in TypeScript:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> collection</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> table</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Moreover, since the function returns an Either , we would need that one too:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">E</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  readonly</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _tag</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#40A02B;font-style:italic;--shiki-dark:#A6D189;--shiki-dark-font-style:italic">Left</span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  readonly</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value0</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> E</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  readonly</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _tag</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#40A02B;font-style:italic;--shiki-dark:#A6D189;--shiki-dark-font-style:italic">Right</span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  readonly</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value0</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">E</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">E</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And then importing the function and calling it from TypeScript:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseJobLocation </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '../output/JobLocation'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseJobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'{ "collection": "col", "document": "doc" }'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (loc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_tag </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Right'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Quite the bother, right? That's why it is most beneficial if the entire critical section can be written in PureScript entirely. In my case, the JobLocation is used for displaying a corresponding UI element (in React), so there's little benefit at a cost of lots of boilerplate and not the best experience defining those parsers.

I personally prefer Scala 3 implementation (not the integration with TypeScript part though, just the JSON parser implementation):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">circe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">circe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">implicits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">effect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IOApp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">circe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">generic</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">semiauto</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">enum</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">collection</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">collection</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">document</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">table</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">object</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  given</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveDecoder</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  given</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveDecoder</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  given</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">TableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveDecoder</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">object</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocationApp</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IOApp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Simple</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  import</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseJobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">jsonString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parse(jsonString).flatMap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      json.as[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">TableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] orElse</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      json.as[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] orElse</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      json.as[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> run</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Unit</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testCases </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">      """{"collection": "users"}"""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">      """{"collection": "orders", "document": "order-123"}"""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">      """{"table": "analytics"}"""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">      """{"invalid": "data"}"""</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    testCases.traverse_ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jsonStr </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      parseJobLocation(jsonStr) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">match</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(location) </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">          IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.println(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">s</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Parsed: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">jsonStr</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -> </span><span style="color:#7C7F93;--shiki-dark:#949CBB">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(error) </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">          IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.println(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">s</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Failed to parse: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">jsonStr</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -> </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">error.getMessage</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

This is a really straightforward implementation in my opinion. In this example, the parsing is literally boiled down to "try parsing TableLocation and if it returns Left , try parsing DocumentLocation instead, and if that returns Left , try parsing CollectionLocation , otherwise return what you got".

Alternatively, circe , the JSON parsing library for scala-cats used in the example above, provides an even neater way:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">object</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JobLocation</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  given</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveDecoder</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  given</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveDecoder</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  given</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">TableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deriveDecoder</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  given</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    summon[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">TableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] or</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    summon[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] or</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    summon[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseJobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">jsonString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    parse(jsonString).flatMap(_.as[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span></span></code>

In this code, the parser for the parent type, JobLocation is defined as a combined parser of whichever case class manages to get parsed first:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">summon[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">TableLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] or</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">summon[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DocumentLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] or</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">summon[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Decoder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CollectionLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]].widen[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JobLocation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span></code>

Just to reiterate, I do understand that converting the application (and developers) to this new weird technology is an almost impossible task, especially in a large long-lived project. One way to reason about it and justify the transition is the resilience requirements of a project (the need for actually error-prone code) and the amount of time and effort spent to date on finding and fixing those nasty bugs and undefined behaviours in an application.

IO impact urn:uuid:b4ae849f-dd6d-52c0-80a9-e93d508a7a73 2024-05-10T00:00:00Z 2024-05-10T00:00:00Z IO impact Artem Shubovych

At MongoDB I work on a Relational Migrator project - a tool which helps people migrate their relational database to MongoDB. And recently we grew interested in the performance of our tool. Due to the nature of the migrations, they are usually extremely long (potentially even never ending, for some scenarios). It is a rather valuable information to know where we can speed things up.

Hence we ran a profiler on a relatively big database of 1M rows. And this was what we saw:

The handleBatch method is where the meat and potatoes of our migration logic reside. It lasts for approx. 6.5 sec . We could have debated on which parts of this flame graph we could optimize (and we actually did), but we first decided to take a quick look at the same graph from the higher level - not the CPU time (when CPU is actually doing the active work) but the total time:

The entire application run took 4,937 sec ( 1hr 22min 17sec ). Of which, the migration itself took only 130 sec :

The biggest chunk of it was writing to MongoDB database at 120 sec :

The actual migration logic is really just 3.5 sec :

So out of 130 sec of the actual migration run, the actual logic took 3.5 sec or mere 2.69% . The rest was just IO (input/output). Which we also saw on the thread timeline:

Most time all the threads spent sleeping.

This is not new information, just a reminder that the slowest part of pretty much any application is input-output.

Simulating network outages in Docker urn:uuid:b7a2c94f-a724-5dbe-b83b-eeaea6054efa 2024-02-08T00:00:00Z 2024-02-08T00:00:00Z Simulating network outages in Docker Artem Shubovych

Recently, for my work project I needed to simulate a system of ours going offline for a period of time (similar to having a network outage on a customer side).

I figured there are two ways to do it:

  • using Docker' networks
  • using host OS' firewall

With Docker network it is as easy as

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">docker</span><span style="color:#40A02B;--shiki-dark:#A6D189"> network</span><span style="color:#40A02B;--shiki-dark:#A6D189"> disconnect</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189">network-nam</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189">container-nam</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

This way you disconnect a container from a network (even if it is a bridge network, exposing the container to the host OS).

You can find a list of networks with docker network ls and list of containers with docker ps .

To roll it back (simulate recovery from an outage), simply

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> docker</span><span style="color:#40A02B;--shiki-dark:#A6D189"> network</span><span style="color:#40A02B;--shiki-dark:#A6D189"> connect</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189">network-nam</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189">container-nam</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

Disconnecting a container from a network is okay, but sometimes you might want to have a fine-grain control over the outage, like forbid a specific IP or port being accessed by your container.

With the firewall it is totally possible, but the steps differ for Linux and OSX.

In Linux you use iptables and control a rule group specific to Docker only:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> iptables</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -I</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DOCKER</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -p</span><span style="color:#40A02B;--shiki-dark:#A6D189"> tcp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --dport</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 27017</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -j</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DROP</span></span></code>

The above command will block all TCP traffic on port 27017 for all Docker containers. To revert this, run

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> iptables</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -I</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DOCKER</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -p</span><span style="color:#40A02B;--shiki-dark:#A6D189"> tcp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> —dport</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 22</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ACCEPT</span></span></code>

To control a specific IP address use the -s parameter:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> iptables</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -I</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DOCKER</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -p</span><span style="color:#40A02B;--shiki-dark:#A6D189"> tcp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -s</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 192.168.0.10</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --dport</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 27017</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -j</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DROP</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> iptables</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -I</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DOCKER</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -p</span><span style="color:#40A02B;--shiki-dark:#A6D189"> tcp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -s</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 192.168.0.10</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --dport</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 27017</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -j</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ACCEPT</span></span></code>

On the other hand, OSX uses a tool with BSD roots, pf . You can use the /etc/pf.conf file to mess with firewall rules.

Blocking traffic is achieved by adding a rule like below to the /etc/pf.conf file:

<code>block drop out quick proto tcp from any to any port 27017
</code>

followed by reloading the rule list with

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> pfctl</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -f</span><span style="color:#40A02B;--shiki-dark:#A6D189"> /etc/pf.conf</span></span></code>

In case pf is disabled, one is enabled running

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> pfctl</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -e</span></span></code>

Re-enabling is as easy as removing (or commenting out) the rule line in the /etc/pf.conf file and reloading it with pfctl -f /etc/pf.conf .

How unique are your bundles? urn:uuid:0d87d9ec-45fc-5d6b-91f5-fab77ab35a60 2024-01-04T00:00:00Z 2024-01-04T00:00:00Z How unique are your bundles? Artem Shubovych

In the modern front-end development we are all used to package managers, transpilation and bundling. These concepts are the biproduct of the tools which we hoped would simplify developer' burden and speed up the development.

However, how confident are you these tools are actually doing good job?

Developers seem comfortable off-loading the processing power to users' machine (browser, predominantly). We are not surprised by seeing slow websites anymore. A simple blog is downloading 55MB of JavaScript? Seems fine nowadays.

I currently work on a fairly small tool ( MongoDB Relational Migrator ), which also utilizes TypeScript, React and, of course, bundling. We use Vite for that. Our bundles are split into chunks (but I have accounted for that, too).

I went ahead and wrote a rather simple script which parses the bundles (using TypeScript compiler API, because why not), extracting the function definitions (both arrow functions and plain old function ) and counts how many times they occur in the file. For this last bit, to make sure I am not counting a => true and x => true as different occurrences, I am minimizing the function definition with uglifyjs and counting the SHA256 hashes of the minimized functions (just to have a reasonable key in my hashmap instead of entire function code).

These are my findings.

Out of 54 chunks, 47 are not css-in-js chunks. Out of 47 remaining, 7 have any significant duplication (over 5%). But when they do, they do it hard: duplication varies between 18% and a whopping 42% of sheer file size. Absolute numbers are also astonishing: 33% to 59% functions are duplicates.

<code>Found 15192 functions, 8963 are unique (59%)
Duplicates length: 1518418 bytes out of 3537579 bytes are duplicate code (42.92%)

Found 1202 functions, 494 are unique (41.1%)
Duplicates length: 130649 bytes out of 340227 bytes are duplicate code (38.4%)

Found 513 functions, 231 are unique (45.03%)
Duplicates length: 50160 bytes out of 136057 bytes are duplicate code (36.87%)

Found 598 functions, 267 are unique (44.65%)
Duplicates length: 57607 bytes out of 164737 bytes are duplicate code (34.97%)

Found 17 functions, 10 are unique (58.82%)
Duplicates length: 1932 bytes out of 6532 bytes are duplicate code (29.58%)

Found 154 functions, 98 are unique (63.64%)
Duplicates length: 11140 bytes out of 45135 bytes are duplicate code (24.68%)

Found 968 functions, 651 are unique (67.25%)
Duplicates length: 52616 bytes out of 281406 bytes are duplicate code (18.7%)
</code>

I thought my code might be wrong, so I looked into the bundle code itself. Here's a short excerpt:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">():</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">yR</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Zce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> bR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bR</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bR</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Wce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> wR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> wR</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">wR</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Uce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> $R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $R</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$R</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Gce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> OR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OR</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#FE640B;--shiki-dark:#EF9F76">OR</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Kce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> xR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xR</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xR</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

See how the following fragment of code repeats multiple times:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

In fact, this exact same fragment of code repeats 137 times in the same piece of bundle chunk (same file):

Repeated function definition in a single chunk of code

By the way, this is a production build of our front-end, built using Vite, with minification enabled.

The raw length of this function code is 146 characters. So in a single place, in a single file, you have 136 * 146 = 19_992 bytes of waste. Meaning, browser has to load these 20KB of code, parse it and create 136 duplicating functions.

Looking at the overall size of 3.5MB of code in this chunk and its insane 41% duplicated code (in sheer bytes, not occurrences, so 1.5MB wasted), imagine how much faster this single file could have been loaded in a browser.

I was keen on seeing what functions get duplicated most often and ran my script on an entire build output directory. Here are top 80-ish offenders:

Function code (minimized) Copies
function(r){for(var t=1;t&#x3C;arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&#x26;&#x26;(r[n]=o[n])}return r} 2205
function n(){return Object.assign&#x26;&#x26;Object.assign.bind(),n.apply(this,arguments)} 1197
function n(){return Object.assign,n.apply(this,arguments)} 1008
function(){} 753
function(i){this.a=i} 250
function(n,e){if(null==n)return{};for(var r,t={},f=Object.keys(n),u=0;u&#x3C;f.length;u++)r=f[u],0&#x3C;=e.indexOf(r)||(t[r]=n[r]);return t} 191
function(e,r){if(null==e)return{};var t,n=function(e,r){if(null==e)return{};for(var t,n={},l=Object.keys(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&#x26;&#x26;(n[t]=e[t]);return n} 187
function(e,r){return r=r||e.slice(0),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(r)}}))} 159
function(n){return this===n} 119
function(r,t){if("object"!=typeof r||null===r)return r;var e=r[Symbol.toPrimitive];if(void 0===e)return("string"===t?String:Number)(r);e=e.call(r,t||"default");if("object"!=typeof e)return e;throw new TypeError("@@toPrimitive must return a primitive value.")} 113
function(r,e,t){return i=function(r,e){if("object"!=typeof r||null===r)return r;var t=r[Symbol.toPrimitive];if(void 0===t)return String(r);t=t.call(r,e);if("object"!=typeof t)return t;throw new TypeError("@@toPrimitive must return a primitive value.")}(e,"string"),(e="symbol"==typeof i?i:String(i))in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r;var i} 111
function(t){t=function(t,r){if("object"!=typeof t||null===t)return t;var i=t[Symbol.toPrimitive];if(void 0===i)return String(t);i=i.call(t,r);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}(t,"string");return"symbol"==typeof t?t:String(t)} 111
function(e,n,r){return n in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,e} 104
function(c,i){He.call(this,c,i)} 94
function(n,r){(null==r||r&#x26;gt;n.length)&#x26;&#x26;(r=n.length);for(var e=0,l=new Array(r);e&#x3C;r;e++)l[e]=n[e];return l} 93
function(){return!0} 92
function(){return!1} 78
function(){return new gt(this)} 77
function(r){if(Array.isArray(r))return r} 77
function(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)} 77
function(t){return t&#x26;&#x26;"object"==typeof t&#x26;&#x26;"default"in t?t:{default:t}} 76
function(i,t){this.a=i,this.b=t} 58
function(){return this.a} 49
function(t,e){var r,n=Object.keys(t);return Object.getOwnPropertySymbols&#x26;&#x26;(r=Object.getOwnPropertySymbols(t),e&#x26;&#x26;(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,r)),n} 49
function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(c,e),Object.defineProperty(y,e,t.get?t:{enumerable:!0,get:function(){return c[e]}}))} 49
function(){return c[b]} 49
function(a,e,i){var r,t=i["aria-label"],n=i["aria-labelledby"],c=i.title;switch(a){case"img":return t||n||c?(l(r={},"aria-labelledby",n),l(r,"aria-label",t),l(r,"title",c),r):{"aria-label":"".concat(e.replace(/([a-z])([A-Z])/g,"$1 $2")," Icon")};case"presentation":return{"aria-hidden":!0,alt:""}}} 49
function(i){Di(this,i)} 48
function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable} 48
function(){throw M(new De)} 46
function(l,r){var t=null==l?null:typeof Symbol&#x3C;"u"&#x26;&#x26;l[Symbol.iterator]||l["@@iterator"];if(null!=t){var n,u,e=[],a=!0,o=!1;try{for(t=t.call(l);!(a=(n=t.next()).done)&#x26;&#x26;(e.push(n.value),!r||e.length!==r);a=!0);}catch(l){o=!0,u=l}finally{try{a||null==t.return||t.return()}finally{if(o)throw u}}return e}} 44
function(n){throw M(new De)} 39
function(r){var n;return r&#x26;&#x26;"object"==typeof r&#x26;&#x26;"default"in r?r:(n=Object.create(null),r&#x26;&#x26;Object.keys(r).forEach(function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(r,e),Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:function(){return r[e]}}))}),n.default=r,Object.freeze(n))} 39
function n(r){return n(r)} 38
function(n){return typeof n} 38
function(o){return o&#x26;&#x26;"function"==typeof Symbol&#x26;&#x26;o.constructor===Symbol&#x26;&#x26;o!==Symbol.prototype?"symbol":typeof o} 38
function(r){var n;return r&#x26;&#x26;r.__esModule?r:(n=Object.create(null),r&#x26;&#x26;Object.keys(r).forEach(function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(r,e),Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:function(){return r[e]}}))}),n.default=r,Object.freeze(n))} 37
function(){return this.b} 33
function(l,r){var t=null==l?null:typeof Symbol&#x3C;"u"&#x26;&#x26;l[Symbol.iterator]||l["@@iterator"];if(null!=t){var e,n,u,a,f=[],i=!0,o=!1;try{if(u=(t=t.call(l)).next,0===r){if(Object(t)!==t)return;i=!1}else for(;!(i=(e=u.call(t)).done)&#x26;&#x26;(f.push(e.value),f.length!==r);i=!0);}catch(l){o=!0,n=l}finally{try{if(!i&#x26;&#x26;null!=t.return&#x26;&#x26;(a=t.return(),Object(a)!==a))return}finally{if(o)throw n}}return f}} 33
function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))} 32
function(n){return Ei(n)} 30
function(n){return L(fn,X,2,n,6,1)} 30
function(n){} 29
function(r){if(typeof Symbol&#x3C;"u"&#x26;&#x26;null!=r[Symbol.iterator]||null!=r["@@iterator"])return Array.from(r)} 28
function(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)} 28
()=>{} 27
function(){return null} 27
function(n,o){e.exports=o(m,on(),dn)} 27
function(i){Fi(this,i)} 23
function(n,o){e.exports=o(dn,on(),m)} 22
function(){throw M(new Fe(Re((xe(),Ds))))} 21
function(){return this} 20
function(i,t){this.b=i,this.a=t} 19
function(n,e){throw M(new De)} 18
function(){return 0} 17
function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))} 16
()=>{var l;return null!=(l=e.options.debugAll)?l:e.options.debugHeaders} 16
function(n){return n} 15
function(c){Kr.call(this,c)} 15
function(){return this.c} 15
function(){return this.d} 15
function(n,r){return n} 14
d=>d.id 14
function(){var r=function(t,o){return(r=Object.setPrototypeOf||({__proto__:[]}instanceof Array?function(t,o){t.__proto__=o}:function(t,o){for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&#x26;&#x26;(t[n]=o[n])}))(t,o)};return function(t,o){if("function"!=typeof o&#x26;&#x26;null!==o)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");function n(){this.constructor=t}r(t,o),t.prototype=null===o?Object.create(o):(n.prototype=o.prototype,new n)}} 14
function(_,o){_.__proto__=o} 14
function(o,r){for(var t in r)Object.prototype.hasOwnProperty.call(r,t)&#x26;&#x26;(o[t]=r[t])} 14
function(n){return!1} 13
function(t){var l=-1,n=null==t?0:t.length;for(this.clear();++l&#x3C;n;){var r=t[l];this.set(r[0],r[1])}} 12
function(a,e,l){var i,r=l["aria-label"],t=l["aria-labelledby"],n=l.title;switch(a){case"img":return r||t||n?(f(i={},"aria-labelledby",t),f(i,"aria-label",r),f(i,"title",n),i):{"aria-label":"".concat(e.replace(/([a-z])([A-Z])/g,"$1 $2")," Icon")};case"presentation":return{"aria-hidden":!0,alt:""}}} 12
a=>a 12
a=>a() 12
function(n,a){n.a=a} 11
function(){ia.call(this)} 11
function(i,t,h){this.a=i,this.b=t,this.c=h} 11
function(n,r){return r} 11
function(){return this.a.gc()} 11
function(e){return e&#x26;&#x26;e.__esModule?e:{default:e}} 11
()=>n(!1) 11
function(i){this.b=i} 10
function(c){this.c=c} 10
function(){return this.f} 10
function(n){return n||"div"} 10
function(n,r,i){var l;return i=null!=(l=i)?l:"div",n||("string"==typeof(null==r?void 0:r.href)?"a":i)} 10

Let's dive deeper, shall we?

Imagine for a second that we could define the duplicated functions once and then just reuse the short name instead (sounds reasonable, does it not?).

But not all of those functions could be de-duplicated in such way (at least not so easily). Some of these functions use the outer closure functions and variables (something defined outside of the function itself), so we can skip these. For instance, function(i){Di(this,i)} and function(){throw M(new De)} can be ignored.

Then, there are function using this . These might be tricky ( this is not what you think is a famous JavaScript mantra).

Lastly, some (if not most) of the functions could be either replaced with arrow functions or standard library function. But that is uncertain - one must understand what a function does first.

With those points in mind, let's look at the offenders once again:

Function code (minimized) Copies Notes
function(r){for(var t=1;t&#x3C;arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&#x26;&#x26;(r[n]=o[n])}return r} 2205 spread operator?
function n(){return Object.assign&#x26;&#x26;Object.assign.bind(),n.apply(this,arguments)} 1197 Object.assign methods?
function n(){return Object.assign,n.apply(this,arguments)} 1008 Object.assign properties?
function(){} 753 no-op
function(n,e){if(null==n)return{};for(var r,t={},f=Object.keys(n),u=0;u&#x3C;f.length;u++)r=f[u],0&#x3C;=e.indexOf(r)||(t[r]=n[r]);return t} 191 ?
function(e,r){if(null==e)return{};var t,n=function(e,r){if(null==e)return{};for(var t,n={},l=Object.keys(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&#x26;&#x26;(n[t]=e[t]);return n} 187 ?
function(e,r){return r=r||e.slice(0),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(r)}}))} 159 ?
function(r,t){if("object"!=typeof r||null===r)return r;var e=r[Symbol.toPrimitive];if(void 0===e)return("string"===t?String:Number)(r);e=e.call(r,t||"default");if("object"!=typeof e)return e;throw new TypeError("@@toPrimitive must return a primitive value.")} 113 ?
function(r,e,t){return i=function(r,e){if("object"!=typeof r||null===r)return r;var t=r[Symbol.toPrimitive];if(void 0===t)return String(r);t=t.call(r,e);if("object"!=typeof t)return t;throw new TypeError("@@toPrimitive must return a primitive value.")}(e,"string"),(e="symbol"==typeof i?i:String(i))in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r;var i} 111 ?
function(t){t=function(t,r){if("object"!=typeof t||null===t)return t;var i=t[Symbol.toPrimitive];if(void 0===i)return String(t);i=i.call(t,r);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}(t,"string");return"symbol"==typeof t?t:String(t)} 111 ?
function(e,n,r){return n in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,e} 104 ?
function(n,r){(null==r||r>n.length)&#x26;&#x26;(r=n.length);for(var e=0,l=new Array(r);e&#x3C;r;e++)l[e]=n[e];return l} 93 array spread?
function(){return!0} 92 always-true
function(){return!1} 78 always-false
function(r){if(Array.isArray(r))return r} 77 self explanatory
function(){throw new TypeError('Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.')} 77 isSymbol ?
function(t){return t&#x26;&#x26;"object"==typeof t&#x26;&#x26;"default"in t?t:{default:t}} 76 ?
function(t,e){var r,n=Object.keys(t);return Object.getOwnPropertySymbols&#x26;&#x26;(r=Object.getOwnPropertySymbols(t),e&#x26;&#x26;(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,r)),n} 49 ?
function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(c,e),Object.defineProperty(y,e,t.get?t:{enumerable:!0,get:function(){return c[e]}}))} 49 ?
function(l,r){var t=null==l?null:typeof Symbol&#x3C;"u"&#x26;&#x26;l[Symbol.iterator]||l["@@iterator"];if(null!=t){var n,u,e=[],a=!0,o=!1;try{for(t=t.call(l);!(a=(n=t.next()).done)&#x26;&#x26;(e.push(n.value),!r||e.length!==r);a=!0);}catch(l){o=!0,u=l}finally{try{a||null==t.return||t.return()}finally{if(o)throw u}}return e}} 44 ?
function(r){var n;return r&#x26;&#x26;"object"==typeof r&#x26;&#x26;"default"in r?r:(n=Object.create(null),r&#x26;&#x26;Object.keys(r).forEach(function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(r,e),Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:function(){return r[e]}}))}),n.default=r,Object.freeze(n))} 39 ?
function n(r){return n(r)} 38 Function.apply ?
function(n){return typeof n} 38 typeof
function(o){return o&#x26;&#x26;"function"==typeof Symbol&#x26;&#x26;o.constructor===Symbol&#x26;&#x26;o!==Symbol.prototype?"symbol":typeof o} 38 ?
function(r){var n;return r&#x26;&#x26;r.__esModule?r:(n=Object.create(null),r&#x26;&#x26;Object.keys(r).forEach(function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(r,e),Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:function(){return r[e]}}))}),n.default=r,Object.freeze(n))} 37 import ?
function(l,r){var t=null==l?null:typeof Symbol&#x3C;"u"&#x26;&#x26;l[Symbol.iterator]||l["@@iterator"];if(null!=t){var e,n,u,a,f=[],i=!0,o=!1;try{if(u=(t=t.call(l)).next,0===r){if(Object(t)!==t)return;i=!1}else for(;!(i=(e=u.call(t)).done)&#x26;&#x26;(f.push(e.value),f.length!==r);i=!0);}catch(l){o=!0,n=l}finally{try{if(!i&#x26;&#x26;null!=t.return&#x26;&#x26;(a=t.return(),Object(a)!==a))return}finally{if(o)throw n}}return f}} 33 ?
function(n){} 29 no-op
function(r){if(typeof Symbol&#x3C;"u"&#x26;&#x26;null!=r[Symbol.iterator]||null!=r["@@iterator"])return Array.from(r)} 28 ?
function(){throw new TypeError('Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.')} 28 ?
()=>{} 27 no-op
function(){return null} 27 always-null
function(){return this} 20 always-this
function(){return 0} 17 always-zero
function(n){return n} 15 identity
function(n,r){return n} 14 always-first-argument
d=>d.id 14 .id
function(){var r=function(t,o){return(r=Object.setPrototypeOf||({__proto__:[]}instanceof Array?function(t,o){t.__proto__=o}:function(t,o){for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&#x26;&#x26;(t[n]=o[n])}))(t,o)};return function(t,o){if("function"!=typeof o&#x26;&#x26;null!==o)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");function n(){this.constructor=t}r(t,o),t.prototype=null===o?Object.create(o):(n.prototype=o.prototype,new n)}} 14 ?
function(_,o){_.__proto__=o} 14 Object.is_a ?
function(o,r){for(var t in r)Object.prototype.hasOwnProperty.call(r,t)&#x26;&#x26;(o[t]=r[t])} 14 ?
function(n){return!1} 13 always-false
a=>a 12 identity
a=>a() 12 call first argument
function(n,a){n.a=a} 11 enum/const definition?
function(n,r){return r} 11 always-second-argument
function(e){return e&#x26;&#x26;e.__esModule?e:{default:e}} 11 import default
function(c){this.c=c} 10 enum/const definition?

As a matter of fact, someone on the internet did a very similar research few years ago. So I hoped to see the improvement in the build tools over the years.

As I mentioned above, our front-end is bundled with Vite. Let's see if using esbuild or bun (since both are fairly new and stand out in terms of architecture and performance) do a better job.

With few small adjustments to make things fair (e.g. build the same thing in the same way), like disabling the plugins for Vite, setting up svgr loader, here are some build time stats:

yarn install :

<code>➤ YN0000: Done with warnings in 17s 798ms
yarn  12.11s user 19.69s system 175% cpu 18.122 total
</code>

bun install :

<code>warn: esbuild's postinstall script took 748.9ms

 1028 packages installed [1.82s]
  Removed: 2
bun install  0.22s user 0.65s system 47% cpu 1.849 total
</code>
Bundler Build time
bun 0.43s
esbuild 2.57s
vite 85.04s
webpack 138.64s

And the analysis of the built bundles:

vite :

<code>Found 968 functions, 651 are unique (67.25%)
Found 598 functions, 267 are unique (44.65%)
Found 154 functions, 98 are unique (63.64%)
Found 17 functions, 10 are unique (58.82%)
Found 15192 functions, 8963 are unique (59%)
Found 1202 functions, 494 are unique (41.1%)
Found 513 functions, 231 are unique (45.03%)
= Total 18644 functions, 10714 are unique (57.4%)

Duplicates length: 52616 bytes out of 281406 bytes are duplicate code (18.7%)
Duplicates length: 57607 bytes out of 164737 bytes are duplicate code (34.97%)
Duplicates length: 11140 bytes out of 45135 bytes are duplicate code (24.68%)
Duplicates length: 1932 bytes out of 6532 bytes are duplicate code (29.58%)
Duplicates length: 1518418 bytes out of 3537579 bytes are duplicate code (42.92%)
Duplicates length: 130649 bytes out of 340227 bytes are duplicate code (38.4%)
Duplicates length: 50160 bytes out of 136057 bytes are duplicate code (36.87%)
= Total 1822522 out of 4511673 bytes are duplicate code (40.3%)
</code>

esbuild :

<code>Found 46654 functions, 28952 are unique (62.06%)
Duplicates length: 6905599 bytes out of 9645594 bytes are duplicate code (71.59%)
</code>

bun :

<code>Found 31113 functions, 25755 are unique (82.78%)
Duplicates length: 446020 bytes out of 5696964 bytes are duplicate code (7.83%)
</code>

webpack :

<code>Found 2898 functions, 1434 are unique (49.48%)
Duplicates length: 320940 bytes out of 4645589 bytes are duplicate code (6.91%)
</code>

And a deeper analysis of the duplicated functions:

esbuild :

Function Copies
function(r){for(var t=1;t&#x3C;arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&#x26;&#x26;(r[n]=o[n])}return r} 2216
function n(){return Object.assign&#x26;&#x26;Object.assign.bind(),n.apply(this,arguments)} 1204
function n(){return Object.assign,n.apply(this,arguments)} 1010
function(){} 844
function(t){return t&#x26;&#x26;"object"==typeof t&#x26;&#x26;"default"in t?t:{default:t}} 260
function(i){this.a=i} 250
function(n,e){if(null==n)return{};for(var r,t={},f=Object.keys(n),u=0;u&#x3C;f.length;u++)r=f[u],0&#x3C;=e.indexOf(r)||(t[r]=n[r]);return t} 203
function(e,r){if(null==e)return{};var t,n=function(e,r){if(null==e)return{};for(var t,n={},l=Object.keys(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&#x26;&#x26;(n[t]=e[t]);return n} 194
function(e,r){return r=r||e.slice(0),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(r)}}))} 160
function(r,t){if("object"!=typeof r||null===r)return r;var e=r[Symbol.toPrimitive];if(void 0===e)return("string"===t?String:Number)(r);e=e.call(r,t||"default");if("object"!=typeof e)return e;throw new TypeError("@@toPrimitive must return a primitive value.")} 137
function(r,e,t){return i=function(r,e){if("object"!=typeof r||null===r)return r;var t=r[Symbol.toPrimitive];if(void 0===t)return String(r);t=t.call(r,e);if("object"!=typeof t)return t;throw new TypeError("@@toPrimitive must return a primitive value.")}(e,"string"),(e="symbol"==typeof i?i:String(i))in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r;var i} 134
function(t){t=function(t,r){if("object"!=typeof t||null===t)return t;var i=t[Symbol.toPrimitive];if(void 0===i)return String(t);i=i.call(t,r);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}(t,"string");return"symbol"==typeof t?t:String(t)} 134
()=>{} 129
function(n){return this===n} 119
function(e,n,r){return n in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,e} 115
function(n,r){(null==r||r>n.length)&#x26;&#x26;(r=n.length);for(var e=0,l=new Array(r);e&#x3C;r;e++)l[e]=n[e];return l} 106
function(c,i){Bs.call(this,c,i)} 94
function(){return!0} 93
function(r){if(Array.isArray(r))return r} 83
function(){throw new TypeError( Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a Symbol.iterator method. )} 83
function(){return!1} 79
function(){return new cu(this)} 77
function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(b,e),Object.defineProperty(E,e,t.get?t:{enumerable:!0,get:function(){return b[e]}}))} 76
function(){return b[P]} 76
function(a,e,l){var i,r=l["aria-label"],t=l["aria-labelledby"],n=l.title;switch(a){case"img":return r||t||n?(s(i={},"aria-labelledby",t),s(i,"aria-label",r),s(i,"title",n),i):{"aria-label":"".concat(e.replace(/([a-z])([A-Z])/g,"$1 $2")," Icon")};case"presentation":return{"aria-hidden":!0,alt:""}}} 76
function(r){var n;return r&#x26;&#x26;r.__esModule?r:(n=Object.create(null),r&#x26;&#x26;Object.keys(r).forEach(function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(r,e),Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:function(){return r[e]}}))}),n.default=r,Object.freeze(n))} 67
function(n){return typeof n} 64
function(o){return o&#x26;&#x26;"function"==typeof Symbol&#x26;&#x26;o.constructor===Symbol&#x26;&#x26;o!==Symbol.prototype?"symbol":typeof o} 64
function n(r){return n(r)} 63
function(t,e){var r,n=Object.keys(t);return Object.getOwnPropertySymbols&#x26;&#x26;(r=Object.getOwnPropertySymbols(t),e&#x26;&#x26;(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,r)),n} 61
function(i,t){this.a=i,this.b=t} 58
function(r){var n;return r&#x26;&#x26;"object"==typeof r&#x26;&#x26;"default"in r?r:(n=Object.create(null),r&#x26;&#x26;Object.keys(r).forEach(function(e){var t;"default"!==e&#x26;&#x26;(t=Object.getOwnPropertyDescriptor(r,e),Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:function(){return r[e]}}))}),n.default=r,Object.freeze(n))} 50
function(r){if(typeof Symbol&#x3C;"u"&#x26;&#x26;null!=r[Symbol.iterator]||null!=r["@@iterator"])return Array.from(r)} 49
function(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)} 49
function(){return this.a} 49
function(i){p0(this,i)} 48
function(l,r){var t=null==l?null:typeof Symbol&#x3C;"u"&#x26;&#x26;l[Symbol.iterator]||l["@@iterator"];if(null!=t){var n,u,e=[],a=!0,o=!1;try{for(t=t.call(l);!(a=(n=t.next()).done)&#x26;&#x26;(e.push(n.value),!r||e.length!==r);a=!0);}catch(l){o=!0,u=l}finally{try{a||null==t.return||t.return()}finally{if(o)throw u}}return e}} 46
function(){throw St(new Ss)} 46
function(n){throw St(new Ss)} 39
()=>{"use strict";Vu(),Du()} 38
function(l,r){var t=null==l?null:typeof Symbol&#x3C;"u"&#x26;&#x26;l[Symbol.iterator]||l["@@iterator"];if(null!=t){var e,n,u,a,f=[],i=!0,o=!1;try{if(u=(t=t.call(l)).next,0===r){if(Object(t)!==t)return;i=!1}else for(;!(i=(e=u.call(t)).done)&#x26;&#x26;(f.push(e.value),f.length!==r);i=!0);}catch(l){o=!0,n=l}finally{try{if(!i&#x26;&#x26;null!=t.return&#x26;&#x26;(a=t.return(),Object(a)!==a))return}finally{if(o)throw n}}return f}} 37
function(){return this.b} 33
function(){X(x)} 32
function(n){} 31
a=>a() 30
function(n){return V1(n)} 30
function(n){return dn(oi,mr,2,n,6,1)} 30
function(){return null} 29
function(){return this} 24
()=>{"use strict";Du()} 23
function(i){g0(this,i)} 23
function(t,r){var e;if(t)return"string"==typeof t?k(t,r):"Map"===(e="Object"===(e=Object.prototype.toString.call(t).slice(8,-1))&#x26;&#x26;t.constructor?t.constructor.name:e)||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?k(t,r):void 0} 22
function(t,r){var e;if(t)return"string"==typeof t?P(t,r):"Map"===(e="Object"===(e=Object.prototype.toString.call(t).slice(8,-1))&#x26;&#x26;t.constructor?t.constructor.name:e)||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?P(t,r):void 0} 22
function(n){return null!=n&#x26;&#x26;n instanceof Array} 21
function(r){if(Array.isArray(r))return P(r)} 21
function(e){return e&#x26;&#x26;e.__esModule?e:{default:e}} 21
function(t,r){var e;if(t)return"string"==typeof t?Q(t,r):"Map"===(e="Object"===(e=Object.prototype.toString.call(t).slice(8,-1))&#x26;&#x26;t.constructor?t.constructor.name:e)||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?Q(t,r):void 0} 21
function(){throw St(new Os(il((qs(),_g))))} 21
function(n){return n} 20
function(n){return null!=n&#x26;&#x26;n.nodeType===Node.ELEMENT_NODE} 20
function(e){throw Error("Received unhandled value: ".concat(e))} 20
function(r,n){return Array.isArray(r)?r.concat(n):"string"==typeof r?r:void 0} 19

bun :

Function Copies
function(){} 739
function(i){this.a=i} 250
function(r){for(var t=1;t&#x3C;arguments.length;t++){var n,o=arguments[t];for(n in o)Object.prototype.hasOwnProperty.call(o,n)&#x26;&#x26;(r[n]=o[n])}return r} 197
()=>{} 141
function(n){return this===n} 119
function(c,f){f7.call(this,c,f)} 94
function(){return!0} 91
function(){return new p9(this)} 77
function(){return!1} 76
function(i,t){this.a=i,this.b=t} 58
function(n,e){if(null==n)return{};for(var r,t={},f=Object.keys(n),u=0;u&#x3C;f.length;u++)r=f[u],0&#x3C;=e.indexOf(r)||(t[r]=n[r]);return t} 53
function(r,t){if("object"!=typeof r||null===r)return r;var e=r[Symbol.toPrimitive];if(void 0===e)return("string"===t?String:Number)(r);e=e.call(r,t||"default");if("object"!=typeof e)return e;throw new TypeError("@@toPrimitive must return a primitive value.")} 51
function(){return this.a} 49
function(e,r){if(null==e)return{};var t,n=function(e,r){if(null==e)return{};for(var t,n={},l=Object.keys(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols)for(var l=Object.getOwnPropertySymbols(e),o=0;o&#x3C;l.length;o++)t=l[o],0&#x3C;=r.indexOf(t)||Object.prototype.propertyIsEnumerable.call(e,t)&#x26;&#x26;(n[t]=e[t]);return n} 48
function(r,e,t){return i=function(r,e){if("object"!=typeof r||null===r)return r;var t=r[Symbol.toPrimitive];if(void 0===t)return String(r);t=t.call(r,e);if("object"!=typeof t)return t;throw new TypeError("@@toPrimitive must return a primitive value.")}(e,"string"),(e="symbol"==typeof i?i:String(i))in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r;var i} 48
function(t){t=function(t,r){if("object"!=typeof t||null===t)return t;var i=t[Symbol.toPrimitive];if(void 0===i)return String(t);i=i.call(t,r);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}(t,"string");return"symbol"==typeof t?t:String(t)} 48
function(i){T6(this,i)} 48
()=>{R3(),G3()} 46
function(){throw x0(new w7)} 46
function(e,r){return r=r||e.slice(0),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(r)}}))} 45
function(n,r){(null==r||r>n.length)&#x26;&#x26;(r=n.length);for(var e=0,l=new Array(r);e&#x3C;r;e++)l[e]=n[e];return l} 41
function(n){throw x0(new w7)} 39
function(r){if(Array.isArray(r))return r} 36
function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")} 36
function(){return this.b} 33
function(n){return n2(n)} 30
function(n){return J1($5,p1,2,n,6,1)} 30
function(t,e){var r,n=Object.keys(t);return Object.getOwnPropertySymbols&#x26;&#x26;(r=Object.getOwnPropertySymbols(t),e&#x26;&#x26;(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,r)),n} 29
function(l,r){var t=null==l?null:"undefined"!=typeof Symbol&#x26;&#x26;l[Symbol.iterator]||l["@@iterator"];if(null!=t){var e,n,u,f,i=[],a=!0,o=!1;try{if(u=(t=t.call(l)).next,0===r){if(Object(t)!==t)return;a=!1}else for(;!(a=(e=u.call(t)).done)&#x26;&#x26;(i.push(e.value),i.length!==r);a=!0);}catch(l){o=!0,n=l}finally{try{if(!a&#x26;&#x26;null!=t.return&#x26;&#x26;(f=t.return(),Object(f)!==f))return}finally{if(o)throw n}}return i}} 29
function(n){} 29
function(){return null} 28
function(e){return Object.getOwnPropertyDescriptor(Z,e).enumerable} 25
function(e){Object.defineProperty(Z,e,Object.getOwnPropertyDescriptor(W,e))} 25
function(n){return n} 23
function(i){C6(this,i)} 23
()=>{G3()} 22
function(){throw x0(new C7(n7((y7(),KG))))} 21
function(){return this} 19
function(i,t){this.b=i,this.a=t} 19
function(n){return!1} 18
function(n,w){throw x0(new w7)} 18
function(){return 0} 17
function(n){return typeof n} 17
function(o){return o&#x26;&#x26;"function"==typeof Symbol&#x26;&#x26;o.constructor===Symbol&#x26;&#x26;o!==Symbol.prototype?"symbol":typeof o} 17
()=>{R3()} 16
()=>{var e;return null!=(e=Z.options.debugAll)?e:Z.options.debugHeaders} 16
function(n,r){return n} 15
function(c){hX.call(this,c)} 15
function(){return this.c} 15
function(){return this.d} 15
function(e,n,r){return n in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,e} 14
function(r){if("undefined"!=typeof Symbol&#x26;&#x26;null!=r[Symbol.iterator]||null!=r["@@iterator"])return Array.from(r)} 14
function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")} 14
d=>d.id 14
()=>W(!1) 13
a=>a 12
function(t){var l=-1,n=null==t?0:t.length;for(this.clear();++l&#x3C;n;){var r=t[l];this.set(r[0],r[1])}} 12
function(n,c){} 12
function(n,r){return r} 11
function(n,a){n.a=a} 11
function(){_V.call(this)} 11
function(i,t,h){this.a=i,this.b=t,this.c=h} 11
function(){return this.a.gc()} 11
function(i){this.b=i} 10
function(c){this.c=c} 10
function(){return this.f} 10

Interestingly enough, all three tools handled the job bad in different aspects:

  • vite was the slowest and produced second biggest bundle
  • esbuild was the fastest and produced the largest bundle
  • bun was slower than esbuild by a split of hair, but produced smallest bundle with least duplicates

Bonus points to bun for installing node modules in a link of an eye.

In terms of duplicates, however, all three failed miserably (in my opinion), with the best result being the bundle produced by bun with 18% duplicates and the rest having almost half the bundle wasted.

For the most part, bundlers seem to be doing a pretty bad job at tree shaking and keep a lot of those utility functions' duplicates. One can estimate how much of a wasted space these use, by multiplying the function code length by the number of duplicates minus one (for one definition).

Let's imagine some of the above functions could be de-duplicated. What are the benefit of that? For the most part, the front-end can load faster for users - simply because there is less bytes to transfer. On top of that, there are less functions to be created in memory. So technically , the front-end can act faster. Although, on the modern machines the difference between having one function and few thousand of the same function is negligible.

Here is a shortened list of top abusers from different bundlers for our tool:

Function vite esbuild bun
# Bytes # Bytes # Bytes
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){}</span></span></code>
753 9036 844 10128 739 8868
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
92 1840 93 1860 91 1820
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
78 1560 79 1580 76 1520
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
27 621 29 667 28 644
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
20 460 24 552 19 437
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
17 340 n/a 0 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
13 273 n/a 0 18 378
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){}</span></span></code>
29 377 31 403 29 377
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
15 315 20 420 23 483
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#179299;--shiki-dark:#81C8BE"> typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 64 1792 17 476
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 119 3332 119 3332
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
14 322 n/a 0 15 345
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
11 253 n/a 0 11 253
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){}</span></span></code>
n/a 0 n/a 0 12 180
<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{}</span></span></code>
27 162 129 774 141 846
<code><span class="line"><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span></span></code>
12 48 n/a 0 12 48
<code><span class="line"><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span></code>
12 72 n/a 0 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">o</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[t]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> o)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(o</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r[n]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">o[n])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
2205 317520 2216 319104 197 28368
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
1197 95760 1204 96320 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
1008 58464 1010 58580 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">l</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)l[e]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[e]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> l</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
93 9672 106 11024 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isArray</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r))</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
77 3157 83 3403 36 1476
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">throw</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> TypeError</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#FE640B;--shiki-dark:#EF9F76">39</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;Invalid attempt to destructure</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">non</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">iterable instance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\nIn order to be iterable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">non</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array objects must have a [Symbol</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">iterator]() method</span><span style="color:#179299;--shiki-dark:#81C8BE">.&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#FE640B;--shiki-dark:#EF9F76">39</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
77 13244 83 14276 36 6192
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#40A02B;--shiki-dark:#A6D189">"object"</span><span style="color:#179299;--shiki-dark:#81C8BE">==typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#40A02B;--shiki-dark:#A6D189">"default"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">default</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
76 5624 260 19240 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">o</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__proto__</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">o</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
14 392 n/a 0 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">o</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(o[t]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r[t])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
14 1176 n/a 0 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__esModule</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">default</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span></code>
11 539 21 1029 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">defineProperty</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">:!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">configurable</span><span style="color:#179299;--shiki-dark:#81C8BE">:!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">writable</span><span style="color:#179299;--shiki-dark:#81C8BE">:!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e[n]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 115 13570 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isArray</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">concat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189">"string"</span><span style="color:#179299;--shiki-dark:#81C8BE">==typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">:void</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 19 1520 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">instanceof</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 21 987 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{};</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">keys</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f[u]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">indexOf</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r)</span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(t[r]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n[r])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 n/a 0 53 6890
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"object"</span><span style="color:#179299;--shiki-dark:#81C8BE">!=typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r[Symbol</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">toPrimitive]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">void</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"string"</span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">String</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Number)(r)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#40A02B;--shiki-dark:#A6D189">"default"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"object"</span><span style="color:#179299;--shiki-dark:#81C8BE">!=typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">throw</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> TypeError</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"@@toPrimitive must return a primitive value."</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 137 36853 51 13719
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">slice</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">freeze</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">defineProperties</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">raw</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">freeze</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 160 17600 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">o</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> o</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#40A02B;--shiki-dark:#A6D189">"function"</span><span style="color:#179299;--shiki-dark:#81C8BE">==typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Symbol</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">o</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">constructor</span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Symbol</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">o</span><span style="color:#179299;--shiki-dark:#81C8BE">!==</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Symbol</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#40A02B;--shiki-dark:#A6D189">"symbol"</span><span style="color:#179299;--shiki-dark:#81C8BE">:typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> o</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 64 7424 n/a 0
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"undefined"</span><span style="color:#179299;--shiki-dark:#81C8BE">!=typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Symbol</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r[Symbol</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">iterator]</span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"@@iterator"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
n/a 0 n/a 0 14 1624

Interestingly enough, aside from a lot of () => {} and (a, b) => a and () => true (as I call them, utility) functions, there are a lot of ES6 / TypeScript helpers such as class definition and spread operator variants, presumingly made to be compatible with ES5-only browsers. Maybe if we had targeted only platforms supporting the latest ES features we would get better results?

Well, not quite much:

bundle sizes:

Bundler Bundle size
bun 5.4M
esbuild 9.2M
esbuild (tuned) 8.0M
vite 7.1M
vite (tuned) 3.8M
webpack 4.4M

vite :

<code>Found 15983 functions, 9581 are unique (59.94%)
Duplicates length: 1495985 bytes out of 4019326 bytes are duplicate code (37.22%)
</code>

esbuild :

<code>Found 41736 functions, 29224 are unique (70.02%)
Duplicates length: 3406606 bytes out of 8347230 bytes are duplicate code (40.81%)
</code>

webpack is (should be) already using the target config option from tsconfig.json (which is set to ESNext in our case) and bun does not really have a whole lot of customization in this regard.

One unlikely possibility when these duplicates can be faster than having just one function is that running the nearly-defined code (in terms of a single block of code) might be slightly faster than making code jumps. This is super far-fetched idea from low-level programming, when CPU does not have to jump thousands or millions of (assembly) instructions back and forth but literally a few instead. This won't justify using verbose ES5-compatible code on ESnext browser, however. How about we run a very synthetic benchmark to check just this one theory?

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">time</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'1'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1000000</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(f)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">timeEnd</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'1'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>
<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">time</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'2'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1000000</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> f</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(f)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">timeEnd</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'2'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The results are actually quite stable:

<code>1: 17029ms
1: 16998ms
1: 16903ms

2: 21877ms
2: 21811ms
2: 21821ms
</code>

Having just one function instance is approx. 23% faster. But what happens at consequitive runs?

<code>1: 9194ms
1: 9159ms
1: 14044ms
1: 13882ms
1: 13975ms
1: 9205ms
1: 14026ms

2: 21821ms
2: 13843ms
2: 13866ms
2: 13854ms
2: 13961ms

2: 21718ms
2: 13952ms
2: 13925ms
2: 13923ms
</code>

Seems like CPU does indeed do a little bit of instruction caching and branch prediction (first run is visibly slower than the subsequent runs). But the observation still holds: having one function definition instead of many copies (even "near" copies) has a much bigger impact.

With that being said, there is one interesting thing to try here: what if we actually replace some of those bulky duplicates with one-time declarations, within the same bundle?

Without performing an in-depth code analysis and optimization, I came up with the following naive implementation:

  1. analyze the code and pick a few functions (biggest abusers) to fix them up
  2. extract all function names, function parameter names (including potential destructuring objects in function params) and all variable and constant names
  3. for each function to be de-duplicated, create a unique name (using the variable and function parameter and function names to avoid any clashes)
  4. from the end of the file to the beginning, remove all occurrences of the function declaration and replace all function references with the unique name
  5. add the function declarations to the beginning of the file

This approach is rather naive, since it does not account for a number of edge cases. For instance, if there are two functions to be replaced:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">l</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[r]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(t </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> l)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(l</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[t]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">l[t])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(p</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">assign</span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">l</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments[r]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(t </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> l)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prototype</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasOwnProperty</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(l</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t)</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e[t]</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">l[t])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

e.g. one includes the other, the algorithm could have potentially evicted cases like this.

Before proceeding further, it is a good idea to test if the cleaned up bundle can safely replace the original one. Hence I just stuffed it in the static assets folder of our project and ran it with the modified bundle.

This way I figured few issues with the naive approach:

  • two function definitions are causing stack overflow:
    • $z=function n(){return Object.assign,n.apply(this,arguments)}
    • $q=function n(){return n=Object.assign&#x26;&#x26;Object.assign.bind(),n.apply(this,arguments)}
  • some of the empty functions are actually used as constructors (ES5-compatible OOP model) which is only discovered by finding the expressions like $FnName.prototype.something = somethingElse;
  • some functions are named and then referenced later in the code
  • some functions are not used at all: Unused aliases

For the shorthand functions I first tried manually fixing them up - had to replace them with $z=function(){return $z=Object.assign.bind(),$z.apply(this,arguments)} alikes. This worked, so I created an AST transformer to handle these one-line return-only functions:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> simplifyFunction</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> fname</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpFilename </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '_tmp'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">writeFileSync</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(tmpFilename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'utf-8'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> root </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createSourceFile</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        tmpFilename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ScriptTarget</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ESNext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        /* setParentNodes */</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rootFnName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isFunctionDeclaration</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isIdentifier</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">escapedText </span><span style="color:#179299;--shiki-dark:#81C8BE">!==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            rootFnName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">escapedText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEachChild</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> child</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (child) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(child)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(root)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rootFnName) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        fs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rmSync</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(tmpFilename)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> transformer</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">sourceFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> visit</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isIdentifier</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">escapedText </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rootFnName) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factory</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createIdentifier</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(fname)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isFunctionDeclaration</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isBlock</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">statements</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isReturnStatement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">statements[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isBinaryExpression</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">statements[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">expression)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> next </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factory</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createFunctionDeclaration</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factory</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createBlock</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factory</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createReturnStatement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factory</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createComma</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factory</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createAssignment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                    ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factory</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createIdentifier</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(fname)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                    node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">statements[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">expression</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                node</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">statements[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">expression</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    ])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">visitEachChild</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(next</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ctx)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">visitEachChild</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ctx)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">visitNode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(sourceFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visit)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createSourceFile</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(tmpFilename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ScriptTarget</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ESNext)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformed </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transform</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ transformer ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newCode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ts</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createPrinter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> omitTrailingSemicolon</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printFile</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(transformed</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> fileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fileName </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpFilename))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rmSync</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(tmpFilename)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newCode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

The transformer is essentially a two-pass processor: it first parses the code and identifies the first function declaration. If none was found - it just returns the original code. If there was a so-called "root function" defined, it then replaces all identifier with that "root function" name with the alias provided as fname . It also replaces the return statements in form of a return something &#x26;&#x26; something() with return alias = something, alias() .

This approach is different from simply using uglifyjs to just try and minimize the code - it is way more complex (compared to just one function call). It results in few extra whitespaces being added. But using uglifyjs messes things up again and TypeScript compiler does not have an option for minimizing the output. But few extra whitespaces are totally acceptable given the much bigger savings from this transformation.

With the constructors I simply excluded them from being de-duplicated. This resulted in 155 fewer substitutions (in Vite mode), which is negligible on the overall scale of the problem.

As for the named functions which are in the global scope and are referenced later down the line, I had to create a list of "backwards-compatible aliases", mapping those old function names onto the new unique names.

I ended up with a three-pass parser-transformer utility (not really "simple script" anymore). The passes being:

  1. figuring out the duplicate function declarations and replacing them from the end to the start of the code (to minimize the chance of writing over the just-changed code)
  2. removing the duplicate global-scope named functions and replacing them with shorthand aliases to the de-duplicated declarations
  3. replace the usages of all known aliases and shorthand-named de-duplicated functions with their corresponding new (generated) names

Other than those, replacing the original bundle with the optimized one worked like a charm!

The results? With the threshold of 20 duplicates or more:

Bundler Before optimization
Bundle size Total functions Unique functions Unique functions, % Duplicate code, %
bun 6.2M 8903 7443 83.6% 0.78%
esbuild 8.7M 13057 10250 78.5% 3.9%
vite 3.9M 3502 2365 67.53% 6.39%
webpack 4.4M 2898 1434 49.48% 6.91%
After optimization
bun 6.2M (same) 7865 (-1038) 7355 (-88) 93.52% (+9.92%) 0.51% (-0.27%)
esbuild 8.5M (-0.2M) 3265 (-9792) 2990 (-7260) 91.58% (+13.08%) 0.62% (-3.28%)
vite 3.6M (-0.3M) 2483 (-1019) 2277 (-88) 91.7% (+24.17%) 1.68% (-4.71%)
webpack 4.1M (-0.3M) 1484 (-1414) 1375 (-59) 92.65% (+43.17%) 0.43% (-6.48%)

In conclusion, the bundlers do a pretty average job at optimizing the bundles, even in production mode with some extra tuning. And if some brave soul is willing to invest even more time and effort than I did into developing a sophisticated solution (potentially improving the existing tools, like uglifyjs or bundlers themselves), the numbers can be improved even further. It would be really interesting to see what would the results be running this optimizer on a bigger bundle.

In my humble opinion, Bun does produce the cleanest bundle. It might be not the smallest one, but it has least unnecessary stuff. On top of that, it is the fastest tool in JS world I have ever used. By the way, this very blog is built using Bun and React SSR - on Github Actions it takes around a minute to build and publish:

Github Actions build and publish with Bun Github Actions build breakdown
TypeScript classes are not what you think urn:uuid:a873e07d-3805-5413-812e-877520fc008c 2023-06-05T00:00:00Z 2023-06-05T00:00:00Z TypeScript classes are not what you think Artem Shubovych

There was a talk at CPPCon 2017 by Matt Goldbolt with an inspirational title, What has my compiler done for me lately? . It actually resonates with me quite a bit, especially in the world where we try to push so hard for statically typed compiled languages on front-end.

Recently I recalled one of (many) aspects why I think TypeScript is useless (as a way to introduce strong type system to JavaScript world) in many cases.

To be realistic and not just throw bare accusations around, this was inspired by the work on contracts for a new microservice, specifically - the request & response types to be used in both client and the back-end of the microservice. The types were similar to the types used on a database layer and one of the developers just returned objects of that DB layer model type on a controller (endpoint) level, which confused me.

Consider the code below:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> moo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> foo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> moo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> foo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> zoo</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> B</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ololo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'1'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This works because of a (rather questionable) design decision by TypeScript team called Type compatibility , where any two classes or interfaces that have overlapping public fields are deemed compatible and can be mutually interplaceable.

However, in most languages with reasonable type system, you would expect two different classes to be just that - two different classes - in the case of a code above, an object of class B can never be assigned to a variable of type A and vice versa.

There is a way to achieve this in TypeScript, however (a bit cumbersome, though): by hiding the properties and only exposing them through non-getter/non-setter methods, when needed:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> moo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> private</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> foo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    getMoo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    getFoo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">foo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> moo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> private</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> foo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> private</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> zoo</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ReadonlyArray</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    getMoo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    getFoo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">foo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    getZoo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zoo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> B</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ololo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'1'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Type 'B' is not assignable to type 'A'. Types have separate declarations of a private property 'moo'.(2322)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Property 'getZoo' is missing in type 'A' but required in type 'B'.(2741)</span></span></code>

Without knowing this "feature" beforehand, one might end up with an inconsistent code or errors down the line (when somebody decides to modify the DB layer model and gets errors on an API layer). And TypeScript does not really help here.

How not to use monads urn:uuid:3443d578-e8a2-586f-91d0-ab6cccd6cb43 2023-01-31T00:00:00Z 2023-01-31T00:00:00Z How not to use monads Artem Shubovych

Recently I have watched a video titled "Optionals and errors in Haskell & Rust - monads by example" . In the video, the author makes a simple application simulating the retrieval of a HTML document via URL and checking if the document contains the title. This is a half-simulated experience, aimed at the beginners to demonstrate how the error handling is done in Rust and Haskell.

However, author in his code has made quite a few bad decisions. And that's what I want to make a focus of this blog: how one should not use monads and handle errors in Haskell.

Author's original source looks like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> DuplicateRecordFields</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #-}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> MultiWayIf</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #-}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OverloadedRecordDot #-}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OverloadedRecordUpdate #-}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Control.Monad</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forM_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Data.List</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isInfixOf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Data.Maybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Text.Printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> deriving</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Show</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  deriving</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Show</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readDoc</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readDoc url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"fail"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Bad read of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          Right </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"head-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-empty"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Doc</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                          Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Title of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                      }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">buildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buildSummary doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> True</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readAndBuildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readAndBuildSummary url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  head </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  title </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty'</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty' doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty''</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty'' doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  doc </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty'</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty' url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> urls </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">"good"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-empty"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "head-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "fail"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  forM_ urls </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Checking </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">https://%s/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- Summary.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readAndBuildSummary url</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Summary: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Title: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- Has title.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readWhetherTitleNonEmpty url</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- let hasTitleSure = either (const False) id $ fromMaybe False &#x3C;$> hasTitle</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitleSure </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe False </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">const Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id hasTitle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Has title: %s vs %s"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitleSure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

He then proceeded to wrapping this code in IO monad and ended up with the following:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> DuplicateRecordFields</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #-}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> LambdaCase</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #-}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> MultiWayIf</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #-}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OverloadedRecordDot #-}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OverloadedRecordUpdate #-}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Control.Monad</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forM_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Data.Functor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">&#x3C;&#x26;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Data.List</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isInfixOf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Data.Maybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Text.Printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> deriving</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Show</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  deriving</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Show</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- readDoc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readDoc</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readDoc url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"fail"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Bad read of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Right </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              if</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"head-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                      Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-empty"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                      Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                      Doc</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Title of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- buildSummary</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">buildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buildSummary doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> True</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- readAndBuildSummary</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readAndBuildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readAndBuildSummary url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readAndBuildSummary'</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readAndBuildSummary' url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  readDoc url </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> True</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readAndBuildSummary''</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readAndBuildSummary'' url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  readDoc url </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x26;></span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">case</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> True</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- isTitleNonEmpty</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  head </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  title </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty'</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty' doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty''</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty'' doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- readWhetherTitleNonEmpty</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    doc </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty'</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty' url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  readDoc url </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty''</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty'' url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty'''</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty''' url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x26;></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x26;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- main</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> urls </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">"good"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-empty"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "head-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "fail"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  forM_ urls </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Checking </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">https://%s/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- Summary.</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    summary </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readAndBuildSummary url</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Summary: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Title: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- Has title.</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readWhetherTitleNonEmpty url</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- let hasTitleSure = either (const False) id $ fromMaybe False &#x3C;$> hasTitle</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitleSure </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe False </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">const Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id hasTitle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Has title: %s vs %s"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitleSure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

I see a few issues with this code:

  1. the abuse of IO monad
  2. the excessive (an I mean unnecessary) use of Maybe monad
  3. too many unnecessary readDoc calls (bear in mind: it is supposed to be a network call + document parse, so quite a heavy function)

Improvements

My suggestions on how to make their code better:

  1. only stick to IO where the function is actually interacting with the external world; in this case this would be either main or readDoc (when it actually makes a network call)
  2. eliminate the abuse of Maybe Bool - in the functions where the Maybe Bool is used ( isTitleNonEmpty and its variations) just Bool would suffice
  3. only call readDoc once and use the result down the pipeline, no need to call it multiple times ( readAndBuildSummary , readWhetherTitleNonEmpty )
  4. reduce the nested if statements to guard expressions
  5. replace the case eitherValue expressions with the either function
  6. remove the dead / unused / unnecessary code (like those duplicated functions - readWhetherTitleNonEmpty' , readWhetherTitleNonEmpty'' and readWhetherTitleNonEmpty''' )

Use IO monad only for the functions which interact with the outside world

IO monad tells compiler and the people who read the code the function operates outside of the program internals. Like actually performing input-output, working with network, operating system, etc.

You can think of any such function as an unsafe part of an application.

In the example above, most of the functions do not comply with that - they are simply a side-effect of poor monad operations and could be easily changed as follows:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  head </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  title </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">buildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buildSummary doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> True</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- there is absolutely no need for this function</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    doc </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- this is also redundant</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readAndBuildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readAndBuildSummary url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- this is the (reduced) existing code</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main__old</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main__old </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "good"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Checking </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">https://%s/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  summary </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readAndBuildSummary url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Summary: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Title: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readWhetherTitleNonEmpty url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- note how the document is only passed down to the functions which actually operate on the document</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- the only two functions using `IO` monad here are `main` and `readDoc`, as both perform input-output operations</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "good"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Checking </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">https://%s/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Summary: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Title: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span></code>

Reduce calls to IO functions

Pure functions must return the exact same value for the same arguments, regardless of how many times they are called.

IO (and a lot of other monads, like Reader , Writer , etc.) work around this rule by changing the outside world. So even though a function technically returns the same value every time, the side-effect of an IO monad can potentially change something elsewhere, outside of the function itself.

This makes the programs non-pure and might cause a lot of negative impact. These side effects are what is thought to be the root of all evils in (functional) programming. They make it hard to figure out what a program actually does. They make the functions and programs hard to test and prove to be correct.

From the performance perspective, if a function actually does change the outside world, it can't be memoized and it won't be optimized by the compiler to only use its result, computed once.

Think calling a function which tries to create a user in a system or drop a database table. This would happen on every call. If you call such function twice, it will most likely fail (due to database failures, hopefully).

But what if the function creates data instead and there are no checks for duplicates in the external system? Like appending a log line. If such function was to be called multiple times, it can quickly bloat the storage. This is a potential security issue as well.

So instead of calling such functions (recap: functions returning IO monad), why not call them once and store the result? Then the entire program can operate on the stored result value.

Of course, there are plethora of cases where such behaviour (calling such functions multiple times) is actually desired. But in the sample code from above, this is not the case.

Check the transformed code from the previous point how this solution is utilized:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "good"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Checking </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">https://%s/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  -- store the result of fetching a document by its URL</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  -- work on the stored value instead of sending an extra HTTP request</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Summary: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Title: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  -- work on the stored value again, preventing one more HTTP request</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span></code>

Eliminate the abuse of Maybe Bool

There's simply no need to go overboard with Maybe in methods which simply check whether something is present or not.

Maybe Bool introduces a tri-state:

  • Just False
  • Just True
  • Nothing

In cases where this is desired, is much better to represent each of the state with a semantic value:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> HeaderPresence</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NoHeader</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> EmptyHeader</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> HasHeader</span></span></code>

This way the code is much easier to follow and debug.

For the sample in question even this approach is redundant - the function simply checks whether the value (title) is present or not, so a simple Bool would suffice:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty__old</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty__old doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  head </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  title </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  not </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null title</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head doc </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main__old</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main__old </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "good"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> None</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty__old doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitleSure </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe False </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">const Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id hasTitle</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Has title: %s vs %s"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitleSure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "good"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Checking </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">https://%s/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  -- a simple True | False value, no need to mess with Maybe</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  -- note: no need to wrap &#x26; unwrap Maybe and Either</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Has title: %s"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Reduce the nested if statements - use guard expressions

The original readDoc function uses a rather unnecessarily bulky if statement:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readDoc</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readDoc url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"fail"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Bad read of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Right </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              if</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"head-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                      Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-empty"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                      Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                      Doc</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Title of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        }</span></span></code>

Haskell provides a built-in language feature for just this case, which really does make code cleaner a lot:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readDoc</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readDoc url</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"fail"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Bad read of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"head-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-missing"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isInfixOf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"title-empty"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Title of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span></code>

Use existing functions on monads instead of case statements

In my experience, for the most part, you want to simply apply a function to a Maybe or an Either .

And, again, for the most part, you either ignore one of the states of the monad (be it Nothing or Left ), or apply a different function to it.

There are handy helper functions for these situations which do make the code cleaner - fromMaybe and either .

Consider few examples:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasTitle__old </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> None</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty__old doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">const None</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty__old</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary__old </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buildSummary doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- needs a nice helper function</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">invalid_summary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either invalid_summary buildSummary</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitle__old </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docOrError </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Left err </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Right doc </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty doc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">const False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty</span></span></code>

End result

Here's what the code looks like when applying all of the above suggestions and tidying up the code:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{-# </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">LANGUAGE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> DuplicateRecordFields</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #-}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Control.Monad</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forM_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Data.List</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isInfixOf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Data.Maybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Text.Printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">newtype</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> deriving</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Show</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">newtype</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_head </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">newtype</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  deriving</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Show</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- helpers for Repl.It is meh with language extensions</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">docHead</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">docHead </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _head</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">headTitle</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Head</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">headTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">summaryTitle</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">summaryTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- implementations</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readDoc</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readDoc url</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "fail"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> `</span><span style="color:#179299;--shiki-dark:#81C8BE">isInfixOf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Bad read of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "head-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> `</span><span style="color:#179299;--shiki-dark:#81C8BE">isInfixOf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> `</span><span style="color:#179299;--shiki-dark:#81C8BE">isInfixOf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-empty"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> `</span><span style="color:#179299;--shiki-dark:#81C8BE">isInfixOf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right Doc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_head </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Title of %s"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">buildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">buildSummary doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docHead doc </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> headTitle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> True</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">invalidSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">invalidSummary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Summary </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readAndBuildSummary</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readAndBuildSummary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either invalidSummary buildSummary</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readAndBuildTitle</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Summary</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readAndBuildTitle summary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">summaryTitle summary</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isTitleNonEmpty doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  not </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> null title</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docHead doc </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> headTitle</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readWhetherTitleNonEmpty</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Either</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Bool</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readWhetherTitleNonEmpty </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> either </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">const False</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isTitleNonEmpty</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- main</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> urls </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">"good"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-empty"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "title-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "head-missing"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "fail"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  forM_ urls </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">url </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Checking </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">https://%s/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    docOrError </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readDoc url</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- Summary</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> summary </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readAndBuildSummary docOrError</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readAndBuildTitle summary</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Summary: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show summary</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Title: %s"</span><span style="color:#179299;--shiki-dark:#81C8BE"> $</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- Has title</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hasTitle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readWhetherTitleNonEmpty docOrError</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    putStrLn </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printf </span><span style="color:#40A02B;--shiki-dark:#A6D189">"  Has title: %s"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">show hasTitle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>
Floyd-Warshall algorithm, revised urn:uuid:56c04238-8fa3-58a8-adac-8e3a27ffee9f 2023-01-12T00:00:00Z 2023-01-12T00:00:00Z Floyd-Warshall algorithm, revised Artem Shubovych

In this blog I would like to brush upon Floyd-Warshall algorithm implementation I have described previously .

See, generally, when explaining Floyd-Warshall algorithm, the graph is given as an adjacency matrix - an V x V matrix, where V is the number of vertices (nodes) in a graph and each matrix value representing the distance between each vertex. For instance, the value G[1][3] = 12 represents the edge from vertex 1 to vertex 3 with the value of 12 .

Aside from adjacency matrix, there are two other common ways to represent a graph:

  • incidence matrix of size V x E for V vertices and E edges, where each row represents an edge value ( G[i][j] > 0 for edge i -> j , G[i][j] &#x3C; 0 for edge j -> i , G[i][j] = 0 for no edge between vertices i and j )
  • adjacency list, where each vertex is represented as an object with a list of its connections

Consider the graph from the previous blog:

It can be represented in three different ways:

adjacency list:

<code>v0: [ [2 -> 1] ]
v1: [ [2 -> 6], [0 -> 7] ]
v2: [ [3 -> 5] ]
v3: [ [1 -> 2] ]
</code>

adjacency matrix:

<code>   |  v0  v1  v2  v3
---+------------------
v0 |   0   0   1   0
v1 |   7   0   6   0
v2 |   0   0   0   5
v3 |   0   2   0   0
</code>

incidence matrix:

<code>   |  e0  e1  e2  e3  e4
---+---------------------
v0 |   0   0   0   7   0
v1 |   0   0   2   0   0
v2 |   1   0   0   0   6
v3 |   0   5   0   0   0
</code>

However, arguably the most common and most memory-efficient way to represent graph in a real-world application would be the adjacency list.

Hence I thought a bit of a revised implementation is needed, since the previous one (aka "classic" implementation) relies on matrices. And those matrices contain quite a bit of unused data. Take the graph above as an example: it has 4 vertices and 5 edges. An adjacency matrix would use 16 numbers, incidence matrix would use 20 numbers and adjacency list would use 5 tuples of 2 numbers ( 10 numbers, so to speak).

"Classic" Floyd-Warshall algorithm implementation constructs an additional matrix for the shortest paths' distances (at most it can reuse the existing one representing the graph itself) and an additional V x V matrix for path reconstruction.

With a graph represented as an adjacency list (or just a list of node objects), the algorithm can use something like a dictionary (or a hashmap) to reduce the memory consumption. Subjectively, it also becomes easier to read and understand the algorithm.

First, we'd need few definitions:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Connections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ToString</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Graph</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Graph</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Path</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> From</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> To</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Distance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">From </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">To </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The Path class is a bit excessive, as it really only needs a list of Node objects, but I decided to make it verbose on purpose - to make it easier to debug.

The algorithm then becomes like this:

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FindAllPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Graph</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MaxValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MaxValue </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MaxValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

One can easily see the separate parts of the algorithm - initializing the intermediate storage (for the paths and distances) and actually finding the shortest paths. It is pretty much the same algorithm as before with the only difference being the use of dictionary instead of a matrix.

Path reconstruction bit is also a little bit different (not too much though):

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Path</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ReconstructPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> allPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">allPaths</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> path </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tempNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tempNode </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nextNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> allPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tempNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Distance </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempNode</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nextNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nextNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        tempNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nextNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now, there is one major improvement we can make to this algorithm. See, when we initialize the dictionaries for paths and distances, we follow the same logic as with the classic implementation, putting in the values for edges which do not exist in a graph:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // this bit will add entries for inexistent edges</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MaxValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

But as a matter of fact, we do not really have to store these values - instead, we could simply have a check whether the needed entry exists in the dictionary or not:

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FindAllPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Graph</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // -- no more unnecessary entries --</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // ++ but one extra check here, to prevent unnecessary iterations ++</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // ++ and one extra check here, to annotate the existence of a new, indirect shortest path between nodeFrom and nodeTo ++</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

For that matter, we don't really need to have a separate dictionary for path reconstruction - since both distance and pathThrough dictionaries serve the same purpose (have the exact same key, but different value), we can smash those two together and use even less memory:

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> through</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FindAllPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Graph</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> through</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Connections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeFrom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pathThrough</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeFrom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodeThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodeTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathThrough</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Essentially, nothing special - just using the tuples for both the intermediate node and the distance for the shortest paths.

And with a tiny bit of a change, path reconstruction:

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Path</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ReconstructPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Node</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> through</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> allPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">allPaths</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ContainsKey</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> path </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tempNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tempNode </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nextNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> allPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tempNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Distance </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nextNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        tempNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nextNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Parser monad urn:uuid:a821bfb9-32c3-5fed-b136-19cd86b77119 2022-12-06T00:00:00Z 2022-12-06T00:00:00Z

Few years ago I did a course project for the "Functional programming" course at Jagiellonian University. The project was to implement a program for solving systems of equations... in Haskell.

For me back then, the entire concept of monads was quite foreign and scary, so I implemented a very crude state machine to parse the equations as strings from STDIN:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parseRow </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reverse coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reverse var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Invalid equation (state: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show state </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "; coefficients: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show coefficients </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "; var_names: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show var_names </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ")"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parseRow </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c_int </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlpha c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">repl_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlpha c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients </span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '='</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlpha c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients </span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">new_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '+'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlphaNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">new_v </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '='</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c_int </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">repl_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">new_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs state coefficients var_names</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">	where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> abs </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head coefficients</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		k_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sign </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		c_int </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> atoi c</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		new_k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c_int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		repl_k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c_int</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">null var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head var_names </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		new_v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseLine</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parseLine s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow s </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span></code>

However, recently I (hopefully) got a grip of monads, so I decided to modify my old project in Haskell to make it prettier.

One of the improvements I made was the parsing part. Since one of the requirements for the course project was to not use any third-party libraries, I decided to stick to this and implement a parser monad.

This proved to be an interesting task and made the entire parsing part quite neat:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equationFactor</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Fraction</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equationFactor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _sign </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factorSign</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    factor </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromMaybe </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zeroOrOne rationalFactor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equationMember</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Fraction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equationMember </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    factor </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> equationFactor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrOne </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    nameFirst </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isAlpha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    nameRest </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isAlphaNum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nameFirst </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nameRest</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- An equation consists of a list of pairs (factor, variable name) and a free member</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equation</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Fraction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)],</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Fraction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    members </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore equationMember</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '='</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    freeMember </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rationalFactor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">members</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freeMember</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

This is all possible thanks to the Parser monad. Under the cut - the implementation details.

Artem Shubovych

Few years ago I did a course project for the "Functional programming" course at Jagiellonian University. The project was to implement a program for solving systems of equations... in Haskell.

For me back then, the entire concept of monads was quite foreign and scary, so I implemented a very crude state machine to parse the equations as strings from STDIN:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseRow</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parseRow </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reverse coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reverse var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Invalid equation (state: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show state </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "; coefficients: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show coefficients </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "; var_names: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> show var_names </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ")"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parseRow </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c_int </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlpha c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">repl_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlpha c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients </span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '='</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlpha c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients </span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">new_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '+'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isAlphaNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">new_v </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '='</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c_int </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">repl_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isNum c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs </span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">new_k </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> var_names</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">	|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> otherwise </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow cs state coefficients var_names</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">	where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> abs </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head coefficients</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		k_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sign </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">head coefficients</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		c_int </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> atoi c</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		new_k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c_int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		repl_k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c_int</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> not </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">null var_names</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head var_names </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">		new_v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseLine</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parseLine s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parseRow s </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span></code>

However, recently I (hopefully) got a grip of monads, so I decided to modify my old project in Haskell to make it prettier.

One of the improvements I made was the parsing part. Since one of the requirements for the course project was to not use any third-party libraries, I decided to stick to this and implement a parser monad.

This proved to be an interesting task and made the entire parsing part quite neat:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equationFactor</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Fraction</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equationFactor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _sign </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factorSign</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    factor </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromMaybe </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zeroOrOne rationalFactor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equationMember</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Fraction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equationMember </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    factor </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> equationFactor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrOne </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    nameFirst </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isAlpha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    nameRest </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isAlphaNum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nameFirst </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nameRest</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- An equation consists of a list of pairs (factor, variable name) and a free member</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equation</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Fraction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)],</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Fraction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    members </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore equationMember</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '='</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    freeMember </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rationalFactor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">members</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freeMember</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

This is all possible thanks to the Parser monad. Under the cut - the implementation details.

This material is heavily based on the Dave Sands' lectures about parsing in Haskell.

The main idea is that a parser is an annotated function from an input string to maybe something (parsing result) and a string (the unparsed part):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">newtype</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> P </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span></code>

Here, P is just the type constructor.

So the function wrapped by the Parser monad takes a String as an input, parses as much as possible and returns what it managed to parse together with the rest of the string, which was not parser. The two possible results hence are Just (a, String) representing the parsed data ( a part of Maybe (a, String) ) and the unparsed remainder of a string ( String part of Maybe (a, String) ). The other possible result is Nothing , meaning the input string can not be parsed with a given parser function.

Based on this explanation, one can build combinations of the parsers using the chaining of the Maybe monad and the boolean logic ( AND and OR operations, predominantly).

Helper functions

There are few trivial parsers which to help on this endeavour:

  • success a - always succeeds, returning a Just (a, str) (some default value and an entire input string) for any input string
  • failure - always fails, returning Nothing for any input string
  • item - parses any one arbitrary character, returning this character wrapped in Just (chr, str) (first character and the rest of the string) if the input string is non-empty or Nothing if the input string is empty
  • parser1 &#x3C;|> parser2 - tries the first parser, parser1 and if it succeeds - returns the result, but if it fails - returns whatever running the second parser, parser2 returns
  • parser1 >>= (\x -> parser2) - chains two parsers together, runs parser1 and passes its output string to the second parser, parser2 ; but since a parser result is a tuple, not just a string that can be passed to the second parser, this function takes a function from the output of the first parser to the second parser
  • parserFn2 &#x3C;*> parser1 - chains two parsers together, runs parser1 (yes, in the reverse order) and applies parserFn2 to the result; where parserFn2 is a function wrapped in a parser ( Parser (a -> a) )

Since a parser is just a function String -> Maybe (a, String) , in order to actually parse something, one needs to run it. Running a parser is as easy as executing a function parse , passing it a parser and an input string:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">success </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"abc"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">failure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse item </span><span style="color:#40A02B;--shiki-dark:#A6D189">"abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'a'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bc"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> success </span><span style="color:#40A02B;--shiki-dark:#A6D189">'!'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'a'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bc"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> success </span><span style="color:#40A02B;--shiki-dark:#A6D189">'!'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'!'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'b'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"c"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'b'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"c"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">success </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "-123"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"123"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">success </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "123"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"23"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

The aforementioned helper functions are defined as following:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">success</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">success a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> P </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">failure</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">failure </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> P </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Char</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">item </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> P </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">  ""</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">chs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> chs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Alternative</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  empty </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> failure</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  p1 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> P </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse p1 str </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Nothing </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse p2 str</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">instance</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Monad</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  p1 </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> P </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#179299;--shiki-dark:#81C8BE"> \</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse p1 str </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p2 a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Nothing </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pure</span></span></code>

Basic parsers

These basic building blocks are then extended with a bit more complex building blocks, which are a little bit more handy for building complex parsers:

  • sat (ch -> Bool) - returns a parser which only succeeds if the first character of a (non-empty) input string satisfies the function ( ch -> Bool )
  • zeroOrMore p - returns a parser which succeeds if the parser p (passed as a param) succeeds on the input string (potentially multiple times) or fails - regardless, the resulting parser will succeed
  • zeroOrOne p - returns a parser which succeeds if the parser p (passed as a param) succeeds exactly once on an input string or if it fails
  • oneOrOne p - returns a parser which succeeds if the parser p (passed as a param) succeeds once or more on an input string

With these building blocks, one can build more complex parsers:

Parsing a digit

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> digit </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sat isDigit</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse digit </span><span style="color:#40A02B;--shiki-dark:#A6D189">"123abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"23abc"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Parsing a number (as a string)

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> numberStr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isDigit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse numberStr </span><span style="color:#40A02B;--shiki-dark:#A6D189">"123abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"123"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"abc"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Since Parser is an instance of Monad , you can use fmap or &#x3C;$> to combine it with other functions:

Parsing a number (as a non-negative number)

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> naturalNumber </span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">; naturalNumber </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> read </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isDigit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse naturalNumber </span><span style="color:#40A02B;--shiki-dark:#A6D189">"123abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">123</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"abc"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Parsiung a potentially negative number

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sign </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zeroOrOne </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> intNumber </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sign</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> naturalNumber</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse intNumber </span><span style="color:#40A02B;--shiki-dark:#A6D189">"-123abc"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">123</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"abc"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

The code above requires a bit of an explanation, I guess. The first part,

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sign </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zeroOrOne </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span></code>

parses a potential - sign at the beginning of a string and returns either 1 or -1 , aka the sign multiplier. The tricky part is fmap (maybe 1 (\_ -> -1)) ... - the zeroOrOne parser will return Maybe a -- that is, Maybe (Maybe a, String) . So if the wrapped part (in this case - sat (== '-') ) is present in the string, it will return Just a (in this case - Just '-' ). Hence we need to cast this Maybe Char to something reasonable - a number would do. We call the maybe helper with two params - the first one is what would be returned if it is applied to Nothing and the second one is a function which will be called on the value wrapped in Just the thing is applied to:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">'-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maybe False </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ch </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">'-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">True</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maybe True </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ch </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ch </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">True</span></span></code>

The fmap bit then applies this function (returned by maybe 1 (\_ -> -1) ) to the value wrapped by the next argument:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#40A02B;--shiki-dark:#A6D189">'-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span></code>

This very same code could be rewritten as follows:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;$></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Finally, the second part:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sign</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> number</span></span></code>

The left part of it is just like the previously rewritten function from fmap to &#x3C;$> , so this entire line can be written down as follows:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sign</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> number</span></span></code>

What it does is applies the (*) function (multiplication) to the value wrapped in the second argument. In this case it is sign , which is a Parser Integer . This is the tricky bit: the type of this expression is not Parser Integer . It is Parser (a -> a) , a parser of a function. This function, wrapped in a Parser type, can be applied to whatever other parser returns and hence chained together. The &#x3C;*> operator, as mentioned before, chains the two parsers. So the entire expression applies the multiplication operation to the value returned by the sign parser and the value returned by the number parser.

TL;DR: the whole thing analyzes the first character of a string (without consuming it) and returns either 1 or -1 ; it then multiplies this value by the number returned by the number parser.

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse intNumber </span><span style="color:#40A02B;--shiki-dark:#A6D189">"-123"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">123</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse intNumber </span><span style="color:#40A02B;--shiki-dark:#A6D189">"123"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#FE640B;--shiki-dark:#EF9F76">123</span></span></code>

Using a &#x3C;|> operator, one can parse integer (both negative and non-negative) numbers in this weird manner:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">negativeNumber </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> >></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> read </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isDigit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positiveNumber </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> read </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;$></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isDigit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">number2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> negativeNumber </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> positiveNumber</span></span></code>
<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse number2 </span><span style="color:#40A02B;--shiki-dark:#A6D189">"-42"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">42</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse number2 </span><span style="color:#40A02B;--shiki-dark:#A6D189">"123"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">123</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Combining parsers

To give a few practical examples of combining the parsers into something meaningful, consider the parser of an integer equation:

<code>-3x1 + 4*x2 = 5
</code>

There are few helpful smaller parsers mentioned above, like intNumber .

But we would need a bit more than that: an equation is a series of members ( -3x1 , 4*x2 ), where each member is a combination of a factor ( -3 , 4 ) and a variable ( x1 , x2 ). There might be either an addition or subtration between members. Lastly, equation must end with an equal sign followed by a free-standing number.

Let's see if we can come up with a plan for this.

We can start at the bottom and define parsers for each bit of an equation or start from the top and define the parser for an entire equation and go down to every member and factor. Let's start with the small bits, the members:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equationMember</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equationMember </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- first, the numeric factor</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    factor </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> equationFactor </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- TODO</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- then, optionally, a multiplication sign, potentially surrounded by any number of whitespace</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrOne </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- followed by the variable name - only letters first, then either letters or numbers</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    nameFirst </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isAlpha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    nameRest </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isAlphaNum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- potentially surrounded by any number of whitespace</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- lastly, return the tuple - numeric factor and the name of a variable</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nameFirst </span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nameRest</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

This should be relatively straightforward to follow. We do not have the equationFactor defined which is used in this parser, so here it is:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equationFactor</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equationFactor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- optionally, a sign (+ or -)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _sign </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factorSign </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- TODO</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- surrounded by any number of whitespace</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- followed by a number</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    factor </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fromMaybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zeroOrOne intNumber</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- combine the numeric factor and a member sign (+ or -) for a final factor number</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_sign </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

The factorSign is yet to be implemented. The reason why I extract it into a separate parser is because one-liner would look ugly:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorSign</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">factorSign </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> positiveSign </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> negativeSign </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;|></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">success </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positiveSign </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '+'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">negativeSign </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fmap </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '-'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span></code>

This works by either matching the + sign and converting it to 1 or matching the - sign and converting it to -1 or succeeding with 1 (by default, when there is no sign).

Lastly, an entire equation parser would be a rather simple combination of the above parsers:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equation</span><span style="color:#179299;--shiki-dark:#81C8BE"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ([(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)],</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">equation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- first, match all the members as a list of tuples (factor, variable name)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    members </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> oneOrMore equationMember</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- potentially surrounded by any number of whitespace, the '=' sign</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    sat </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '='</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    zeroOrMore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sat isSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- the last, free-standing member</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    freeMember </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> intNumber</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- finally, return the tuple of members and a free-standing member</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">members</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> freeMember</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

You can try it on the equation from the example above:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse equation </span><span style="color:#40A02B;--shiki-dark:#A6D189">"-3x1 + 4*x2 = 5"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(([(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"x1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"x2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)],</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

The finished project contains a little bit more - it implements rational calculus (rational factors instead of just pure integers). The entire code is also hosted on GitHub .

ConfigScript urn:uuid:a36d23cf-48e5-5c49-95c1-4014254efddd 2022-11-07T00:00:00Z 2022-11-07T00:00:00Z

Once upon a time I thought OGRE was overly too complicated - all those unnecessary script files, custom formats, a ton of setup hassle. That was until I tried figuring out an entire modern 3D rendering stack from scratch. That's when I realized configuring a rendering process (rendering pipeline) can be tricky. And that's when I realized configuring application with config files can be helpful. OGRE suddenly became very appealing to me and I really began to appreciate all the work the devs have put into it.

One good aspect of OGRE was the "unnecessary" script and configuration files. But the syntax of those files looked much cleaner than that of JSON:

<code>// This is a comment
object_keyword Example/ObjectName
{
    attribute_name "some value"

    object_keyword2 "Nested Object"
    {
        other_attribute 1 2 3
        // and so on..
    }
}
</code>

I thought if I could harvest anything from OGRE into my OpenGL application, that would be the configuration based on this format (rather than Lua or whatever scripts).

Hence I crafted this simple grammar in ANTLR4 to parse these files:

<code class="language-g4">grammar ConfigScript;

config : (object | comment)* EOF ;

object
    : Identifier '{' property* '}'
    | Identifier STRING '{' (property)* '}'
    ;

property : Identifier propertyValue ;

propertyValue
    : vector
    | INT
    | FLOAT
    | BOOL
    | STRING
    | objectValue
    ;

objectValue
    : '{' property* '}'
    | STRING '{' (property)* '}'
    ;

vector
    : INT+
    | FLOAT+
    ;

comment : LINE_COMMENT | BLOCK_COMMENT ;

STRING : DOUBLE_QUOTED_STRING | SINGLE_QUOTED_STRING ;

BOOL : 'true' | 'false' ;

DOUBLE_QUOTED_STRING : '"' DoubleQuoteStringChar* '"' ;
SINGLE_QUOTED_STRING : '\'' SingleQuoteStringChar* '\'' ;

Identifier : ALPHA (ALPHA | NUM)* ;

fragment SingleQuoteStringChar : ~['\r\n] ;
    // : ~['\\\r\n]
    // | SimpleEscapeSequence ;

fragment DoubleQuoteStringChar : ~["\r\n] ;
    // : ~["\\\r\n]
    // | SimpleEscapeSequence ;

// fragment SimpleEscapeSequence : '\\' ['"?abfnrtv\\] ;

INT : '0'
    | '-'? [1-9] [0-9]*
    ;

FLOAT : ('+' | '-')? NUM+ '.' NUM+ ;

WHITESPACE : [ \r\n\t]+ -> skip ;
ALPHA : [a-zA-Z_] ;
NUM : [0-9] ;

LINE_COMMENT : '//' ~[\r\n]* -> skip ;
BLOCK_COMMENT : '/*' .*? '*/' -> skip ;
</code>

The only difference is that the object name can only be a quoted string:

<code>// This is a comment
object_keyword "Example/ObjectName" // &#x3C;--- this can not be just Example/ObjectName
{
    attribute_name "some value"

    object_keyword2 "Nested Object"
    {
        other_attribute 1 2 3
        // and so on..
        /* block comment */
    }
}
</code>

The only thing left with this parser thing is to compile it and use in a project.

Artem Shubovych

Once upon a time I thought OGRE was overly too complicated - all those unnecessary script files, custom formats, a ton of setup hassle. That was until I tried figuring out an entire modern 3D rendering stack from scratch. That's when I realized configuring a rendering process (rendering pipeline) can be tricky. And that's when I realized configuring application with config files can be helpful. OGRE suddenly became very appealing to me and I really began to appreciate all the work the devs have put into it.

One good aspect of OGRE was the "unnecessary" script and configuration files. But the syntax of those files looked much cleaner than that of JSON:

<code>// This is a comment
object_keyword Example/ObjectName
{
    attribute_name "some value"

    object_keyword2 "Nested Object"
    {
        other_attribute 1 2 3
        // and so on..
    }
}
</code>

I thought if I could harvest anything from OGRE into my OpenGL application, that would be the configuration based on this format (rather than Lua or whatever scripts).

Hence I crafted this simple grammar in ANTLR4 to parse these files:

<code class="language-g4">grammar ConfigScript;

config : (object | comment)* EOF ;

object
    : Identifier '{' property* '}'
    | Identifier STRING '{' (property)* '}'
    ;

property : Identifier propertyValue ;

propertyValue
    : vector
    | INT
    | FLOAT
    | BOOL
    | STRING
    | objectValue
    ;

objectValue
    : '{' property* '}'
    | STRING '{' (property)* '}'
    ;

vector
    : INT+
    | FLOAT+
    ;

comment : LINE_COMMENT | BLOCK_COMMENT ;

STRING : DOUBLE_QUOTED_STRING | SINGLE_QUOTED_STRING ;

BOOL : 'true' | 'false' ;

DOUBLE_QUOTED_STRING : '"' DoubleQuoteStringChar* '"' ;
SINGLE_QUOTED_STRING : '\'' SingleQuoteStringChar* '\'' ;

Identifier : ALPHA (ALPHA | NUM)* ;

fragment SingleQuoteStringChar : ~['\r\n] ;
    // : ~['\\\r\n]
    // | SimpleEscapeSequence ;

fragment DoubleQuoteStringChar : ~["\r\n] ;
    // : ~["\\\r\n]
    // | SimpleEscapeSequence ;

// fragment SimpleEscapeSequence : '\\' ['"?abfnrtv\\] ;

INT : '0'
    | '-'? [1-9] [0-9]*
    ;

FLOAT : ('+' | '-')? NUM+ '.' NUM+ ;

WHITESPACE : [ \r\n\t]+ -> skip ;
ALPHA : [a-zA-Z_] ;
NUM : [0-9] ;

LINE_COMMENT : '//' ~[\r\n]* -> skip ;
BLOCK_COMMENT : '/*' .*? '*/' -> skip ;
</code>

The only difference is that the object name can only be a quoted string:

<code>// This is a comment
object_keyword "Example/ObjectName" // &#x3C;--- this can not be just Example/ObjectName
{
    attribute_name "some value"

    object_keyword2 "Nested Object"
    {
        other_attribute 1 2 3
        // and so on..
        /* block comment */
    }
}
</code>

The only thing left with this parser thing is to compile it and use in a project.

ANTLR version incompatibility

It's bragging time! For C++ users, life was never easy. Yet, some good samaritan created the CMake thing. It is ugly as heck, it is barebones and it does not really simplify the life by a whole lot, yet it allows devs to somehow manage build process a bit better than Makefiles. But it is one more tool to learn, keep up-to-date and hate. Then, Microsoft came up with a package manager for C++, vcpkg. And they decided to integrate it with CMake, which became quite popular back then. One more tool to learn, keep up-to-date and hate. But not as much as CMake - this one actually helps quite a bit. Like when you have to add a library or two to your project, it becomes much easier than using barebones CMake. And that's where we come to a point of keeping the thing up-to-date. The vcpkg repository is technically community-driven. Meaning people from all around the world are responsible for keeping repository in good shape, but only Microsort-approved (employed?) people can approve merges to the repo. And often this only happens when somebody has to use the port (dependency from vcpkg repo) and sees an issue and has enough time and passion to go and fix it up.

That's a long brag, but the thing is: if you go to ANTLR4 website and just download the JAR and use it to generate the parser & lexer sources for your C++ project, you won't get it to work with the runtime from vcpkg (unless somebody stands up and updates the port). The thing is: vcpkg port provides runtime for ANTLR4 4.10.1 , while the generator on ANTLR4 website has version 4.11.1 . This is an issue, since between these two versions, there were breaking changes in the ANTLR4 runtime source, so the code generated by the newer version can not be used with the newer version of runtime. Simply because classes were moved around or even created, like ::antlr4::internal::OnceFlag , which never existed in 4.10.1 but was added in 4.11.1 together with an entire header file and namespace.

Luckily, some good guy by a gesture of sheer good will created a PR to fix the issue (by updating the version of ANTLR in vcpkg repository), which should be merged in by the time this blog will be published.

You have to match the ANTLR4 source generator version with the version of the runtime provided by the vcpkg port.

Actual implementation

That thing aside, there are few tricks when using the port in the code.

For the vcpkg port, the vcpkg.json file should contain the antlr4 dependency:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">$schema</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "antlr-configscript-cpp"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">version-string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "0.1.0"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">dependencies</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">      "antlr4"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The CMakeFile.txt however should look for antlr4-runtime package, link the antlr4_shared or antlr4_static library and explicitly add the include directories from the internal variable, ${ANTLR4_INCLUDE_DIR} :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.20 FATAL_ERROR)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(antlr_configscript_cpp VERSION 0.1.0 LANGUAGES CXX)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(antlr_configscript_cpp</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "main.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "gen_parser/ConfigScriptLexer.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "gen_parser/ConfigScriptLexer.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "gen_parser/ConfigScriptParser.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "gen_parser/ConfigScriptParser.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "gen_parser/ConfigScriptBaseListener.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "gen_parser/ConfigScriptBaseListener.h"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set_property</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">TARGET</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> antlr_configscript_cpp PROPERTY CXX_STANDARD 20)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">// linking ANTLR4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(antlr4-runtime CONFIG REQUIRED)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(antlr_configscript_cpp PRIVATE antlr4_shared)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(antlr_configscript_cpp PRIVATE ${ANTLR4_INCLUDE_DIR})</span></span></code>

With those issues sorted out, the code to parse the source for the grammar is relatively straightforward:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;iostream></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;antlr4-runtime.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "gen_parser/ConfigScriptLexer.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "gen_parser/ConfigScriptParser.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "gen_parser/ConfigScriptBaseListener.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#pragma</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> execution_character_set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"utf-8"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> configSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> R"(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">// This is a comment</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">object_keyword "Example/ObjectName" // &#x3C;--- this can not be just Example/ObjectName</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">{</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    attribute_name "some value"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    object_keyword2 "Nested Object"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        other_attribute 1 2 3</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        // and so on..</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        /* block comment */</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    }</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">}</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">)"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ANTLRInputStream </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">configSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ConfigScriptLexer </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lexer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CommonTokenStream </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lexer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ConfigScriptParser </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ParseTree</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">config</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toStringTree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Parse Tree: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This program would yield an abstract syntax tree looking like this:

<code>(config (object object_keyword "Example/ObjectName" { (property attribute_name (propertyValue "some value")) (property object_keyword2 (propertyValue (objectValue "Nested Object" { (property other_attribute (propertyValue (vector 1 2 3))) }))) }) &#x3C;EOF>)
</code>

Now, what do we do with it? Well, first we need to implement our own version of ConfigScriptBaseListener :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyConfigListener</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ConfigScriptBaseListener</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterConfig</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ConfigContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitConfig</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ConfigContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterObject</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ObjectContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitObject</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ObjectContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterProperty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PropertyContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitProperty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PropertyContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterPropertyValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PropertyValueContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitPropertyValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PropertyValueContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterObjectValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ObjectValueContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitObjectValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ObjectValueContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">VectorContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">VectorContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterComment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CommentContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitComment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CommentContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> enterEveryRule</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ParserRuleContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exitEveryRule</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ParserRuleContext</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ctx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> visitTerminal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">TerminalNode</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> visitErrorNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ErrorNode</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Then we need to pass an instance of this new class to the TreeWalker so that we can process the tree node-by-node:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> listener </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">MyConfigListener</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> walker </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ParseTreeWalker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">walker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">walk</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">listener</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

But for that to properly work, we'd need to handle every context separately - meaning whenever we enter a nested tree node (like IntVector ), we would want to have the pointer to a this temporary vector to be able to add elements to. And when we exit this node, we would need a pointer to whatever the parent of that vector was, to be able to add this vector to that parent.

This might get out of hand quite quickly.

Alternatively, and arguably more convenient way to handle this is using attributes and actions in the grammar itself:

<code class="language-g4">grammar ConfigScript;

@header {
    #include &#x3C;variant>
    #include &#x3C;any>
}

config : objects=object* EOF ;

object
    returns [
        std::string name
    ]
    : Identifier objectValue { $name = $Identifier->getText(); }
    ;

property
    returns [
        std::string name,
        std::any value
    ]
    : Identifier propertyValue { $name = $Identifier->getText(); antlrcpp::downCast&#x3C;ObjectValueContext*>(_localctx->parent)->propertyMap[$name] = $value; }
    ;

propertyValue
    : intVector { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $intVector.elements; }
    | floatVector { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $floatVector.elements; }
    | INT { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = std::stoi($INT.text); }
    | FLOAT { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = std::stof($FLOAT.text); }
    | BOOL { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = static_cast&#x3C;bool>($BOOL.text == "true"); }
    | STRING { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $STRING.text; }
    | objectValue { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $objectValue.propertyMap; }
    ;

objectValue
    returns [
        std::string classifier,
        std::map&#x3C;std::string, std::any> propertyMap
    ]
    : '{' property* '}'
    | STRING '{' (property)* '}' { $classifier = $STRING.text; }
    ;

intVector
    returns [ std::vector&#x3C;int> elements ]
    : INT+ { auto v = $ctx->INT(); std::for_each(v.begin(), v.end(), [&#x26;](auto* node) { _localctx->elements.push_back(std::stoi(node->getText())); }); }
    ;

floatVector
    returns [ std::vector&#x3C;float> elements ]
    : FLOAT+ { auto v = $ctx->FLOAT(); std::for_each(v.begin(), v.end(), [&#x26;](auto* node) { _localctx->elements.push_back(std::stof(node->getText())); }); }
    ;
</code>

This way we couple the parser with the specific language (C++ in this case), but this allows us to write bare minimum code afterwards:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objects </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> antlrcpp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">downCast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ConfigContext</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

However, there quite a few tricks involved.

First of all, the huge benefit is that this way we are free to specify code to be run on entering each rule and we have an access to all of the rule context:

<code class="language-g4">propertyValue
    : intVector { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $intVector.elements; }
    | floatVector { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $floatVector.elements; }
    | INT { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = std::stoi($INT.text); }
    | FLOAT { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = std::stof($FLOAT.text); }
    | BOOL { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = static_cast&#x3C;bool>($BOOL.text == "true"); }
    | STRING { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $STRING.text; }
    | objectValue { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $objectValue.propertyMap; }
    ;
</code>

See how the nested rules are referenced by their names ( intVector is accessed with $intVector , INT is accessed with $INT , rule text is accessed via $RULE.text ). There is also the current rule' context available through _localctx .

All of this logic is injected into the code generated by ANTLR, so you can access it as-is and see what is available and what not.

But the issue is: whatever the code is that you write in the rules, it won't be compiled when generating the parser code - it would be inserted into the generated code as-is. You will have to make sure it compiles as a separate step.

Some of the rules allow you to define what other data will can be accessed (like the integer value of an INT rule or elements of the intVector rule):

<code class="language-g4">intVector
    returns [ std::vector&#x3C;int> elements ]
    : INT+ { auto v = $ctx->INT(); std::for_each(v.begin(), v.end(), [&#x26;](auto* node) { _localctx->elements.push_back(std::stoi(node->getText())); }); }
    ;
</code>

This also acts as the initialization of the additional context fields.

Second, all of these antlrcpp::downCast&#x3C;Context*>(_localctx->parent) are required to access the parent context (so no $parent or something).

Accessing attribute: $vector.value even though it is not valid C++ code, since $vector will be resolved to a context pointer ( VectorContext* ), hence we have to use all those antlrcpp::downCast .

Accessing repeated rules as a vector: $INT.begin() and $INT.end() would resolve in something else (see the above, accessing attribute). Hence a trick is to access it via context: $ctx->INT().begin() .

Accessing parent attribute:

<code class="language-g4">propertyValue
    : vector { $property::value.emplace($vector.elements); }
</code>

The $property::value won't work and will throw missing code generation template NonLocalAttrRefHeader . I am unsure how to fix this correctly (this should be valid, according to documentation), so I hacked my way through:

<code class="language-g4">propertyValue
    : vector { antlrcpp::downCast&#x3C;PropertyContext*>(_localctx->parent)->value = $vector.elements; }
</code>

And a simple program that prints out the parsed config:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;iostream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;map></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;variant></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;antlr4-runtime.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "gen_parser/ConfigScriptLexer.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "gen_parser/ConfigScriptParser.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "gen_parser/ConfigScriptBaseListener.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#pragma</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> execution_character_set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"utf-8"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printAny</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">any</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#179299;--shiki-dark:#81C8BE"> typeid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(str){ "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any_cast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " };"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#179299;--shiki-dark:#81C8BE"> typeid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(int){ "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any_cast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " };"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#179299;--shiki-dark:#81C8BE"> typeid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(float){ "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any_cast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " };"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#179299;--shiki-dark:#81C8BE"> typeid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any_cast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">vector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(int[]){ "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ", "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " };"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#179299;--shiki-dark:#81C8BE"> typeid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any_cast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">vector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(float[]){ "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ", "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " };"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#179299;--shiki-dark:#81C8BE"> typeid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">any</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">any_cast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">any</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "(obj){ "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " = "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            printAny</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " };"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> configSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> R"(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">// This is a comment</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">object_keyword "Example/ObjectName" // &#x3C;--- this can not be just Example/ObjectName</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">{</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    attribute_name "some value"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    object_keyword2 "Nested Object"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        other_attribute 1 2 3</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        // and so on..</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        /* block comment */</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    }</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">}</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">)"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ANTLRInputStream </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">configSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ConfigScriptLexer </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lexer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CommonTokenStream </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lexer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ConfigScriptParser </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    antlr4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ParseTree</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">config</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toStringTree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Parse Tree: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objects </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> antlrcpp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">downCast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ConfigScriptParser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ConfigContext</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Objects found: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> o </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "["</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> o</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "] { "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectValue </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> o</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">objectValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> propertyMap </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">propertyMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> propertyMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " = "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            printAny</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " } "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Hope this gives you a brief introduction into ANTLR4 and some of the tips on implementing your own parsers.

OpenGL: advanced samples urn:uuid:abe50ab3-104f-546f-8d86-e20fc4980665 2022-10-26T00:00:00Z 2022-10-26T00:00:00Z

Damn this blog was long coming - I picked my interest in shaders over a decade ago, started to actually learn something in early 2021 and started writing this blog at the end of 2021. Now the time has finally come to share this with the world!

For a long time I was keen in learning low-level computer graphics APIs and algorithms, but only recently actually made any progress towards that goal. I have spent few weeks if not months learning about shaders, graphics pipeline and rendering techniques, so this write-up was long forecoming. There might be some mistakes, since I am not an expert in CG and OpenGL and there is a big chunk missing, namely rendering animated 3D models, compute shaders and tesselation, but I hope to fix those in the future.

One might ask: why OpenGL? Why not Vulkan (or DirectX 12)? Why even bother with these emulaiton techniques - why not jump straight to raytracing? Well, it is the end of October 2022 at the moment of publishing this blog, the most recent GPU on the market is GeForce RTX 4090, which is yet to arrive and its RRP (recommended retailer price) is A$2959 (as advertised by nVidia):

RTX4090 price as of October 2022

And most of those cards are gone in a blink of an eye and used for mining whatever-coins. My PC runs GTX1080, which is still more than enough for most of the games I play (being Genshin Impact at most).

I think it is still not a widely spread consumer market, and whilst raytracing, DLSS and all those fine things sound super cool and nice, it is still a niche market. That is not to say I won't be looking into that in the near future. I just think OpenGL still has place in this world, at least as a starting point to build a decent understanding of the modern graphics pipeline, some basic rendering techniques and justify switching to more recent APIs. OpenGL as well as DirectX 11 are still a very feasible fallback for those sytems which do not run top-notch hardware or are struggling running those massive open-world games in anything higher than 1080p@60fps.

In this blog I will try to condense the knowledge I have acquired. I will skip most basic parts such as initializing context, creating window and so on, since most of the tutorials and articles on the Internet focus on those topics. Unlike most tutorials and articles out there, this blog will be all about rendering techniques .

This article was heavily inspired by few blogs on russian website ( Habr ), namely "super-modern OpenGL" ( part 1 and part 2 ) - they are quite messy and lack a lot of material on really interesting topics (again, rendering techniques). This blog partially builds on top of those two and uses a lot more other materials (references provided).

This blog is enormous, so blow is the table of contents for the topics covered. Feel free to jump straight to the topic that picks your interest, screenshots are provided:

The source code is available on GitHub .

Artem Shubovych

Damn this blog was long coming - I picked my interest in shaders over a decade ago, started to actually learn something in early 2021 and started writing this blog at the end of 2021. Now the time has finally come to share this with the world!

For a long time I was keen in learning low-level computer graphics APIs and algorithms, but only recently actually made any progress towards that goal. I have spent few weeks if not months learning about shaders, graphics pipeline and rendering techniques, so this write-up was long forecoming. There might be some mistakes, since I am not an expert in CG and OpenGL and there is a big chunk missing, namely rendering animated 3D models, compute shaders and tesselation, but I hope to fix those in the future.

One might ask: why OpenGL? Why not Vulkan (or DirectX 12)? Why even bother with these emulaiton techniques - why not jump straight to raytracing? Well, it is the end of October 2022 at the moment of publishing this blog, the most recent GPU on the market is GeForce RTX 4090, which is yet to arrive and its RRP (recommended retailer price) is A$2959 (as advertised by nVidia):

RTX4090 price as of October 2022

And most of those cards are gone in a blink of an eye and used for mining whatever-coins. My PC runs GTX1080, which is still more than enough for most of the games I play (being Genshin Impact at most).

I think it is still not a widely spread consumer market, and whilst raytracing, DLSS and all those fine things sound super cool and nice, it is still a niche market. That is not to say I won't be looking into that in the near future. I just think OpenGL still has place in this world, at least as a starting point to build a decent understanding of the modern graphics pipeline, some basic rendering techniques and justify switching to more recent APIs. OpenGL as well as DirectX 11 are still a very feasible fallback for those sytems which do not run top-notch hardware or are struggling running those massive open-world games in anything higher than 1080p@60fps.

In this blog I will try to condense the knowledge I have acquired. I will skip most basic parts such as initializing context, creating window and so on, since most of the tutorials and articles on the Internet focus on those topics. Unlike most tutorials and articles out there, this blog will be all about rendering techniques .

This article was heavily inspired by few blogs on russian website ( Habr ), namely "super-modern OpenGL" ( part 1 and part 2 ) - they are quite messy and lack a lot of material on really interesting topics (again, rendering techniques). This blog partially builds on top of those two and uses a lot more other materials (references provided).

This blog is enormous, so blow is the table of contents for the topics covered. Feel free to jump straight to the topic that picks your interest, screenshots are provided:

The source code is available on GitHub .

Setting up

Just to get this out of the way: I have used few available libraries to simplify my work. You can totally use anything else in your projects with greater success, these were just my decisions which seemed right for me at that time.

  • SFML to manage the window creation, input and loading images
  • globjects to simplify some of the OpenGL entity management (framebuffers, textures, shader programs, vertex attribute objects and buffers)
  • glm for maths (algebra and matrices, predominantly)
  • assimp to load 3D models

The project uses CMake to handle the build process and vcpkg to manage the dependencies. I have also tried xmake but because it lacks IDE support (I have used Visual Studio) , it did not quite fit me.

In these projects I have tried to utilize the new C++ features (C++17 onwards) as much as possible, but I might be missing few great improvements it gives (mostly around containers and memory ownership) .

I also have implemented a sample of using imgui for user interface way down the line as I thought it was not all that helpful for my projects, but apparently, I could have saved myself a lot of debugging time if I added few windows and buttons here and there. Hence I encourage you to look into that too.

Basics I promised not to focus on

Again, to get this out of the way and not go into too much detail on these topics, few words on how I approached OpenGL from my very much outdated background (think OpenGL ver. 1) .

Getting started with SFML

Creating a window and handling user input pretty much remained the same:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;SFML/Window.hpp></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#ifdef</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> SYSTEM_DARWIN</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> videoMode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">VideoMode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1536</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> videoMode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">VideoMode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 768</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#endif</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Window </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">videoMode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello SFML Window!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isOpen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Event event </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pollEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Closed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">close</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Getting started with globjects

The approach to rendering has changed drastically in past decades: from passing each vertex and its attributes to OpenGL it has grown to better suit modern graphics cards' architectures and now looks like passing chunks of data to be stored in the graphics memory and calling graphics driver to run pre-compiled programs on the GPU.

In order to run the program on GPU, it first needs to be compiled from the source. And just like any ordinary program for CPU, the program for GPU (called "shader program" or just "shader") has multiple stages when it runs - you can think about these stages as stages in a big data processing pipeline - you get some input and tell your executor (GPU in this case) how to process and transform the data. This pipeline, however, has few pre-defined stages with pre-defined (to some extent) input and output formats. The stages we will be using in all our samples are:

  1. vertex shader stage - takes a bunch of vertices with bunch of attributes as flat integer or float numbers or packs of 2, 3 or 4 of those numbers, aka vectors; it transforms those vertices (if needed, generally transforms vertices as if they were seen by the "camera") and returns each vertex with attributes assigned to each vertex (the attributes could be arbitrary - numbers or vectors)
  2. geometry shader stage - takes each vertex and produces the geometry it will be part of (think lines, triangles or polygons); returns new vertices with vertex attributes assigned to each vertex (numbers or vectors)
  3. fragment shader stage - takes each geometry (line or triangle) formed by multiple vertices with attributes assigned to each vertex and projects them onto screen (or texture, aka "render target"), returning a pixel data suitable for each render target (one target - one type of pixel data accepted)

There are more of those stages, but those are the most commonly used ones. Each of them is customizable by a separate shader. That is, OpenGL will throw an error if you try to return fragment shader data from vertex shader.

The way you render anything on the screen is: you take a bunch of vertices in 3D space, assign them some data (like the color or normal or texture coordinates), pack them into a buffer object (that is, just a buffer full of data). You then have to tell OpenGL what the data format is. This is done using vertex attribute object - this is essentially a descriptor, telling OpenGL how it should read and process the bytes stored in the buffer.

Here's a comprehensive example of a simple shader initialization and rendering:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;fstream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;iostream></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glbinding/gl/gl.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/Buffer.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/Error.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/Program.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/Shader.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/VertexArray.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/VertexAttributeBinding.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/base/File.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/base/StaticStringSource.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;globjects/globjects.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glm/vec2.hpp></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;SFML/OpenGL.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;SFML/Window.hpp></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#ifdef</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> WIN32</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> namespace</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#endif</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ContextSettings settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">depthBits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 24</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stencilBits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">antialiasingLevel </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">majorVersion </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">minorVersion </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attributeFlags </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ContextSettings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Attribute</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#ifdef</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> SYSTEM_DARWIN</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> videoMode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">VideoMode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1536</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> videoMode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">VideoMode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 768</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#endif</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Window </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">videoMode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello OpenGL!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Style</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> settings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">init</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([](</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> char*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Context</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFunction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">DebugMessage</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // enable automatic messages if KHR_debug is available</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">DebugMessage</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([](</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DebugMessage</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[DEBUG] "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Initializing..."</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cornerBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Creating shaders..."</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Compiling vertex shader..."</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexShaderSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/vertex.glsl"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexShaderSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_VERTEX_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Compiling fragment shader..."</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentShaderSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/fragment.glsl"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentShaderSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FRAGMENT_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Linking shader programs..."</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderingProgram </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Program</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    renderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Creating VAO..."</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vao </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">VertexArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    cornerBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            { </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_STATIC_DRAW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAttribute</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cornerBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFormat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "done"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[INFO] Done initializing"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isOpen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Event event </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pollEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Closed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">close</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        glClear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GL_DEPTH_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glViewport</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        renderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawArrays</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TRIANGLE_STRIP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        renderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">display</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

vertex shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> corner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">corner </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">corner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Camera and getting started with glm

A lot of operations are described as mathematical operations on bunch of vectors with the use of matrices.

Most of the transformations could be done on either CPU (think C++ code) or GPU (think shader code). But keep in mind: if you do a certain operation in vertex shader - it will be executed for each vertex you render with that shader. If you do it in fragment shader - it will be executed for each pixel rendered. Those numbers might be really big and vastly different (for a simple scene with just a plane - 4 vertices vs 1024 * 768 = 786432 pixels, for a big scene - say 2K objects with 3M vertices = 2*10^3 * 3*10^6 = 6*10^9 vertices vs same 786432 pixels).

GLSL comes packed with quite a lot of mathematical operations already, whilst for C++ we can use glm to handle all those nitty-gritty matrix multiplications and inverse matrix calculations.

In order to communicate some data from the CPU to the shader running on GPU, you can use uniform variables.

Here's a simple example of camera implementation with glm:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glm/ext/matrix_clip_space.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glm/ext/matrix_transform.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glm/gtx/rotate_vector.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glm/mat4x4.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glm/vec2.hpp></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;glm/vec3.hpp></span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fov </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 45.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraMoveSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraRotateSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 cameraPos </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 cameraUp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 cameraRight </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 cameraForward </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cross</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraUp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraRight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Clock clock</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isOpen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // measure time since last frame, in seconds</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaTime </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">clock</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">restart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">asSeconds</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2 currentMousePos </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Mouse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Mouse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2 mouseDelta </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentMousePos </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Mouse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Vector2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> horizontalAngle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mouseDelta</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaTime </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraRotateSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fov</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> verticalAngle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mouseDelta</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaTime </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraRotateSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fov</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        cameraForward </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rotate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraForward</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> horizontalAngle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraUp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        cameraForward </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rotate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraForward</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> verticalAngle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraRight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        cameraRight </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rotate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraRight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> horizontalAngle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraUp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isKeyPressed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">W</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            cameraPos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraForward </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraMoveSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isKeyPressed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            cameraPos </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraForward </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraMoveSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isKeyPressed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            cameraPos </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cross</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraForward</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraUp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraMoveSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isKeyPressed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Keyboard</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            cameraPos </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cross</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraForward</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraUp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraMoveSpeed </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 projection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">perspective</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">radians</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fov</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">            0.1f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">            100.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 view </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            cameraPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            cameraPos </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraForward</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            cameraUp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        renderProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"model"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        renderProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"view"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        renderProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projection"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        glClear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GL_DEPTH_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glViewport</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        renderProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawArrays</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TRIANGLE_STRIP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        renderProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">display</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

vertex shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Optimization techniques

Passing data to the shader

Bear in mind: if you want to pass just few bits of data - it is fine to use few uniforms, but if you want to pass a lot of data (think few matrices and lists of data) - you're much better off using buffers. That is, uniform buffer objects (UBO) or even better - shader shared buffer objects (SSBO) - the latter can store much larger amounts of data (according to OpenGL standard guarantees, UBO can store up to 16 kB whilst SSBO - up to 128 MB , but most drivers will let you store up to graphic card's memory limit) and you can have arrays of data in SSBOs. Coupled with user-defined data structures (think struct but in GLSL), you can pass, for example, list of light sources' descriptors to your shader with SSBO.

Here's how you can do it:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> alignas(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PointLightDescriptor</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec4 color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PointLightDescriptor</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLights</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.75f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.85f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.75f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightDataBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLights</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DYNAMIC_COPY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isOpen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindBase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // bind a shader</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

fragment shader:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PointLight</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer PointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    PointLight pointLight</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        PointLight light </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec3 lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">light</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">position </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Deferred rendering

Rendering directly to the output (window), also known as "direct rendering", is not very optimal with most techniques (especially post-processing and special effects). For the most part I will try to use technique called "deferred rendering", where you first render your entire scene into multiple textures with the same size as the output window and then you apply various techniques to those textures - this way you do not have to render entire scene multiple times.

Since you can have multiple render targets, you can render just one fragment (pixel) attribute to one render target and then use it in local post-processing calculations. Trick is: you render scene once. In the geometry shader, you render each vertex' data to a different render target. Then you will not need to process each vertex, but each pixel instead. If you want to calculate shadows or reflections or bloom - you will only have to do it for each pixel, not for each vertex, which might save you heaps of GPU resources.

Batch geometry rendering

You can pack the vertex data for your scene however you want. For example, you can have one buffer with just the vertices' positions and another buffer with just vertices' normals (and so on for each of the vertex attributes). But if the geometry you are trying to render is not changing with time, you can store all the data in one buffer - you just have to tell OpenGL how the bytes are packed in the buffer. For example, you can have position, followed by normal, followed by texture coordinates. You just tell OpenGL to have three attributes - one of the size of 3 floats, the next one of the size of three floats and the last one of the size of two floats.

Moreover, you can store multiple objects' vertices in one buffer! The reason for that would be to minimize the number of buffer and shader switching OpenGL has to make in order to render a certain amount of geometry.

You can combine rendering multiple different geometries with instanced rendering and use glMultiDrawElementsIndirect with a list of "drawing commands" to render a whole lot of geometry from buffers stored in GPU memory.

Top it up with the fact that you can store the draw commands in a buffer and you can generate this buffer using compute shaders (not covered yet) and you can have a rendering engine which works almost entirely on the GPU, saving you a lot of synchronization and communication between CPU and GPU.

To understand how the glMultiDrawElementsIndirect works, one must understand the concept of a draw command and how it works in DirectX 12 and Vulkan. The idea is that you prepare all the geometry and the supporting data, store it in video memory and then only tell GPU to render all that mess in a specific order. This way you don't need to send huge chunks of data from CPU to GPU every frame - this spares computer quite some work.

The draw command describes which chunks of data that are already stored in video memory to use for rendering and how to render them.

A typical draw command is represented as the following C++ structure:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StaticGeometryDrawCommand</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementCount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of elements (triangles) to be rendered for this object</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> instanceCount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of object instances</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> firstIndex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // offset into GL_ELEMENT_ARRAY_BUFFER</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> baseVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // offset of the first object' vertex in the uber-static-object-buffer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> baseInstance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // offset of the first instance' per-instance-vertex-attributes; attribute index is calculated as: (gl_InstanceID / glVertexAttribDivisor()) + baseInstance</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

The issue with this approach is: how to pass the per-instance data? Since all the data used by glDrawMulti* is per-vertex. SSBOs to the rescue!

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> alignas(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StaticObjectData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2 albedoTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2 normalTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2 emissionTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> instanceDataOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> alignas(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> StaticObjectInstanceData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 transformation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// create two arrays: per-object data and per-instance data</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">StaticObjectData</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">StaticObjectInstanceData</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_objectInstanceData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// duck</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // TODO: automate this</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .albedoTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .normalTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .emissionTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .instanceDataOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectInstanceData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .transformation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mat4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// lantern</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .albedoTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .normalTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .emissionTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .instanceDataOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectInstanceData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .transformation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">translate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// scroll</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .albedoTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .normalTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .emissionTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .instanceDataOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectInstanceData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .transformation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">translate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// pen</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .albedoTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">512</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 512</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .normalTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">512</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 512</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .emissionTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            .instanceDataOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectInstanceData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .transformation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">translate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// generate object data buffer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectDataBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DYNAMIC_COPY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// generate object **instance** data buffer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectInstanceDataBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectInstanceDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_objectInstanceData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DYNAMIC_COPY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span></code>

Note how object data contains the texture sizes - this is done so that all the textures can be stored in one texture array (aka 3D texture). This allows for easy texture indexing (using object index instead of having some arbitrary number of texture variables), making this approach extensible. But texture arrays have a limitation: you can have as many textures as you would like in one array, but all textures must have same width and height. However, that does not mean all the pixels matter - you can store smaller textures using their original size and just ignore the rest of the texture data. But in order to do that, you would need to sample the texture with a scale factor. See the shader code below for details.

Then, for even more performance boost, you can put all objects' data into one big data buffer - since we will use drawing commands to render, we can not worry about different buffers. That is, each buffer's element will contain all the necessary vertex data - position, normal and UV coordinates. However, we will still need a separate buffer for indices:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">StaticGeometryDrawCommand</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_drawCommands</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NormalizedVertex</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2 uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NormalizedVertex</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalizedVertexData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> baseVertex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scene </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scenes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">meshes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> numVertices </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPositions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">size_t</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> numVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPositions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normals</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">uvs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            normalizedVertexData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ .position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .uv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        m_indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        StaticGeometryDrawCommand drawCommand </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            .elementCount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            .instanceCount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // TODO: generate commands dynamically whenever the data is changed</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            .firstIndex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            .baseVertex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> baseVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            .baseInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        m_drawCommands</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">drawCommand</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        baseVertex </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> numVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vao </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">VertexArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// generate draw command buffer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> drawCommandBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">drawCommandBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_drawCommands</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DYNAMIC_DRAW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // draw commands can technically be changed</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// generate vertex data buffer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> geometryDataBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">geometryDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normalizedVertexData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_STATIC_DRAW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAttribute</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">geometryDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> offsetof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NormalizedVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NormalizedVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of elements in buffer, stride, size of buffer element</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFormat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of data elements per buffer element (vertex), type of data</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAttribute</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">geometryDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> offsetof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NormalizedVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NormalizedVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of elements in buffer, stride, size of buffer element</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFormat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of data elements per buffer element (vertex), type of data</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAttribute</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">geometryDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> offsetof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NormalizedVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NormalizedVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of elements in buffer, stride, size of buffer element</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">binding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFormat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // number of data elements per buffer element (vertex), type of data</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// generate element buffer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">elementBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_STATIC_DRAW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindElementBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">elementBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span></code>

Rendering is then as simple as binding those buffers and calling glMultiDrawElementsIndirect :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">drawCommandBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DRAW_INDIRECT_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindBase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectInstanceDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindBase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">multiDrawElementsIndirect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TRIANGLES</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_UNSIGNED_INT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    m_drawCommands</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">simpleProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">drawCommandBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DRAW_INDIRECT_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectInstanceDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vao</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Vertex shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">460</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    flat </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">uint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    flat </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">uint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> instanceID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ObjectData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 albedoTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 normalTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 emissionTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    uint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> instanceDataOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // use this field to get instance data: StaticObjectInstanceData.transformation[StaticObjectData.objectData[gl_DrawID].instanceDataOffset + gl_InstanceID]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer StaticObjectData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ObjectData</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer StaticObjectInstanceData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mat4</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformations</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectID </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_DrawID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">instanceID </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_InstanceID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    uint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectInstanceIndex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gl_DrawID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">instanceDataOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_InstanceID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mat4 model </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformations</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectInstanceIndex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">460</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    flat </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">uint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    flat </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">uint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> instanceID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ObjectData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 albedoTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 normalTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 emissionTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    uint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> instanceDataOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer StaticObjectData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ObjectData</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2DArray</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> albedoTextures</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2DArray</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalTextures</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2DArray</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionTextures</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 maxTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">albedoTextures</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 uvFactor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> objectData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">albedoTextureSize </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxTextureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 uv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uvFactor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 albedo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">albedoTextures</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">objectID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> albedo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Read more:

Texture handles

This optimization allows you to spare those glActivateTexture and referring textures by some magical numbers. You create a texture once and freeze its params by using the handles (so you can not change texture params once you have started using its handle), but what you gain is one handle, stored as a 64-bit number (roughly: texture address in GPU memory) which you can then pass to multiple shaders without bothering with those texture IDs.

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// create texture - nothing changes here</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_BORDER_COLOR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// copy texture to GPU memory; this could be done once (not on each frame render) to save some time</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// at this stage, texture parameters (dimensions, filtering, wrapping, etc.) can not be changed anymore - you would have to create a new texture</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// remove texture from GPU memory</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeNonResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Rendering to different textures in geometry shader

A neat trick to render scene multiple times to different textures (for instance, rendering into cubemap) is to use geometry shader - you simply bind multi-layer texture (cubemap or a texture array) and use the gl_Layer output variable in the geometry shader to write to a specific texture layer:

C++ program:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> alignas(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// prepare the shader program with vertex, geometry and fragment shaders</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingVertexSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/shadow-mapping-point.vert"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingVertexShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingVertexSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingVertexShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_VERTEX_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingVertexShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingVertexShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">compile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile point shadow mapping vertex shader"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingGeometrySource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/shadow-mapping-point.geom"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingGeometryShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingGeometrySource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingGeometryShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_GEOMETRY_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingGeometryShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingGeometryShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">compile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile point shadow mapping fragment shader"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingFragmentSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/shadow-mapping-point.frag"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingFragmentShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFragmentSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingFragmentShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FRAGMENT_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingFragmentShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFragmentShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">compile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile point shadow mapping fragment shader"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingProgram </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Program</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingVertexShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingGeometryShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingFragmentShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// prepare the cubemap texture</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMapTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_BORDER_COLOR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glTexImage2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_X </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// prepare the framebuffer</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_ATTACHMENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// prepare a list of six view projection matrices</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 cameraProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">perspective</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">radians</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fov</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 cameraView </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    cameraPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    cameraPos </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraForward</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    cameraUp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">perspective</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">radians</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">90.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapSize </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightProjectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PointLightData pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightProjectionViewMatrices </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// store the view projection matrices in SSBO</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightDataBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DYNAMIC_COPY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// bind framebuffer and shared stored buffer object with parameters</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindBase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// render entire scene</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

geometry shader:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gl_Layer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertex </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_in</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            EmitVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        EndPrimitive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Rendering techniques

Shadow mapping

The most straightforward idea of implementing shadow mapping is: you render a scene depths (each pixel represents a distance from camera to the object) from the perspective of a light source to a separate render target. Then you render your scene normally from the perspective of a camera and for each pixel you compare its distance to the light source (take position of a pixel and subtract position of a light source from it) - if scene pixel is further from the light than the same pixel' depth in the light space - there's some other thing blocking the light, so this pixel is in the shadow.

For this algorithm, you would need a shadow map texture and a framebuffer it is attached to:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_BORDER_COLOR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> framebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDrawBuffers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NONE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Renderbuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">renderBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">storage</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH24_STENCIL8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachRenderBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_STENCIL_ATTACHMENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span></code>

Then you render the entire scene to that framebuffer from the position of the light using the orthographic projection and setting the viewport to the shadow map' size:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 lightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // cameraPos;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 lightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ortho</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 lightView </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 lightSpaceMatrix </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glViewport</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glClearColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glClear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GL_DEPTH_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// same as</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// framebuffer->clearBuffer(static_cast&#x3C;gl::GLenum>(GL_COLOR_BUFFER_BIT | GL_DEPTH), 0, glm::vec4(1.0f));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glEnable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_TEST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glEnable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CULL_FACE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// cull front faces to prevent peter panning the generated shadow map</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glCullFace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FRONT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightSpaceMatrix"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"model"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> chickenModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTransformation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// render scene</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glEnable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CULL_FACE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glCullFace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_BACK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Finally, you restore the viewport to the window (screen) size and render the scene, taking data from shadow map into consideration:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glViewport</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glClearColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glClear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GL_DEPTH_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightPosition"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightColor"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ambientColorUniform->set(glm::vec3(1.0f, 1.0f, 1.0f));</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// materialSpecularUniform->set(12.0f);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"cameraPosition"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projection"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraProjection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"view"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightSpaceMatrix"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// render the scene again</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Shadow mapping vertex shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Shadow mapping fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_FragDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_FragCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Final rendering pass vertex shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Final rendering fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 shadowMapCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ambient</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 ambient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.3</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // diffuse</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // specular</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 viewDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 halfwayDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> viewDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> halfwayDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 64.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 specular </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // calculate shadow</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lighting </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specular</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ambient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lighting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This technique, however, introduces a number of artifacts.

The simplest and easily solved issue is the rough edge of the shadow where there should be none, caused by the bounds of the light projection matrix. One can simply add a check in the shader to see if the pixel is out of the shadow map bounds and light those pixels by default.

Shadow aliasing - when you are trying to render a whole lot of objects on a small texture, shadow edges have stair-like shape instead of smooth lines. The bigger the shadow map, the more cube-like shadows will become. These artifacts are addressed by a number of different techniques, like cascaded shadow maps (aka parallel-slice aka parallel-split shadow mapping).

Sometimes you might see lines of shadows where there should be none. This is caused by the lack of precision of the shadow map - the depth values simply do not have enough data to represent that half-of-a-pixel depth. This could be somewhat mitigated by adding a small factor to the depth sampled from a shadow map. But such a solution presents a yet new artifact - peter-panning, when the objects rendered "fly" over a surface beneath them. Sometimes light might "bleed" through the objects, lighting the surfaces where they should be in the shadow. This artifact is also known as "light bleeding".

There are other algorithms addressing the above artifacts - PCF and variance shadow mapping.

Biasing

This technique fixes the aliasing issue by "offsetting" the surface the shadow is cast upon by some small number (realistically you do not offset anything - you just adjust the calculations).

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 shadowMapCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // this biasing fixes aliasing artifact, but introduces peter-panning</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.05</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.005</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This fixes the aliasing, indeed, but introduces the peter-panning effect, making object appear flying or hovering over the surface upon close inspection.

Percentage-close filtering

Percentage-close filtering, or PCF, is a technique of smoothing out those hard-edge shadows. Instead of calculating whether the pixel (say, on a surface) is in shadow or not you calculate the median of all the neighbours of an are around that pixel (say, 5x5 pixels).

PCF is implemented in the final shadow rendering fragment shader:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 shadowMapCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // this biasing fixes aliasing artifact, but introduces peter-panning</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.05</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.005</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // PCF</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 texelSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pcfDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> texelSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pcfDepth  </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Variance shadow mapping

Variance shadow mapping is yet another technique of smoothing hard shadows. Unlike PCF, it has constant computation time. The idea is that you calculate the probability of a pixel being in shadow. If the probability is high enough - you treat it as if it was in the shadow. For the calculations, the two numbers (called "moments") are calculated during the shadow mapping, essentially being a function of the pixel depth (in light space) and a function of the same depth, squared. During the final scene rendering, you substitute the values in Chebyshev's inequality to get the probability.

The implementation is as simple as having the following shadow mapping fragment shader:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> linearizeDepth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> depth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">farPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> depth </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">farPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> linstep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> _min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> _max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> clamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_max </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> reduceLightBleeding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> p_max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Amount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // Remove the [0, Amount] tail and linearly rescale (Amount, 1].</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> linstep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Amount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p_max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// compute an upper bound on the probability that the currently shaded surface (at depth t) is occluded</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ChebyshevUpperBound</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // One-tailed inequality valid if t > Moments.x</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // Compute variance</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> variance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    variance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">variance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.001</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // Compute probabilistic upper bound</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> variance </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">variance </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 shadowMapCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 shadowMapSample </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 moments </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapSample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // alternatively, use linearizeDepth(shadowMapCoord.z);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // Compute the Chebyshev upper bound.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> step</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentDepth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mu </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sigma2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moments</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0002</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mu</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p_max </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sigma2 </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sigma2 </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">d </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    p_max </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> clamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p_max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> reduceLightBleeding</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p_max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Cascaded shadow mapping

This is rather quality- and performance-optimization technique. It could also be used for not just shadow mapping, but for various objects rendering (like rendering grass, small terrain details, terrain itself, etc.). The idea is that there is no need to render high-detailed shadows further from the camera. Assume you have a large landscape. If you render detailed shadows for an entire landscape to rather limited texture - you will end up having each object have big pixelated shadow. Whilst you want objects closer to the camera look sharp and nice. And the trees in the distance - well, there is no need for them to have that nice shadows.

Thus, you "divide" your camera space into few sections (aka "cascades") and render shadows for each of those cascade separately, using the same size of the shadow map texture. The trick is that the cascade closest to the camera is the smallest, so the shadows have very high level of detail. The section of a camera space a bit further away is larger, but since the shadow map has the same size - the quality of shadows is lower. The furthest section of the camera space has the largest size, so the quality of the shadows in the same size of the shadow map will be the worst. But since the objects in that section are also furthest away from the camera - they don't have to have the most detailed shadows. In fact, you can go even further and only split half of camera space into three (or more, if you will) cascades, leaving the other half, the furthest one from the camera, completely out of the shadow mapping process. This way the objects far away won't even have any shadows at all.

Read more:

For the most part, the logic is implemented in the main application, where you have to set up the projection matrices for the shadow mapping and run the shadow mapping rendering stage multiple times (for each of the projection matrix).

Alternatively, this could be used in conjunction with other two optimization techniques - SSBO and geometry shader - you send the projection matrices to the shader via SSBO and then instead of issuing rendering commands multiple times from the application side (CPU), everything is done on the GPU, without the need to switch back and forth between shader context and application context (roughly put - without the need to formally finish the rendering, let the CPU / application know about this and make it issue a new bunch of rendering commands, which essentially will be the same - just the projection matrix will be different).

Setting up shadow mapping shaders:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingVertexSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/shadow-mapping.vert"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingVertexShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingVertexSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingVertexShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_VERTEX_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingVertexShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingVertexShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">compile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile vertex shader"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingGeometrySource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/shadow-mapping.geom"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingGeometryShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingGeometrySource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingGeometryShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_GEOMETRY_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingGeometryShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingGeometryShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">compile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile geometry shader"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingFragmentSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/shadow-mapping.frag"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingFragmentShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingFragmentSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingFragmentShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FRAGMENT_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingFragmentShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingFragmentShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">compile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile fragment shader"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingProgram </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Program</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMappingVertexShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingGeometryShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingFragmentShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingModelTransformationUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"modelTransformation"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingLightViewProjectionMatrices </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightViewProjectionMatrix"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightViewProjectionMatricesUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightViewProjectionMatrix"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

And a few constants:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightViewProjectionMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splitDepths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.05f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.2f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// these vertices define view frustum in screen space coordinates</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">constexpr</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _cameraFrustumSliceCornerVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Then, the shadow mapping stage:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    lightViewProjectionMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">clear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    splitDepths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">clear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 proj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inverse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _entireFrustum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _cameraFrustumSliceCornerVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _cameraFrustumSliceCornerVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _entireFrustum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        [</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">proj</span><span style="color:#7C7F93;--shiki-dark:#949CBB">](</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">vec3</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec4 v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> proj </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumEdgeDirections </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _frustumEdgeDirections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_entireFrustum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _entireFrustum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _depth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splitIdx </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splitIdx </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">splitIdx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // frustum slice vertices in world space</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumSliceVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _entireFrustum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumEdgeDirections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _depth </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">splitIdx </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _entireFrustum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumEdgeDirections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _depth </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">splitIdx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // TODO: also check if camera is looking towards the light</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumSliceVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceCenter </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _frustumSliceCenter </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_frustumRadiusVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumSliceVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_frustumRadiusVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _frustumRadiusVector </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // calculate new light projection</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 _forward </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 _right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cross</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_forward</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_up</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 _lightView </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_frustumSliceCenter </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_frustumRadiusVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _up</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumRadius </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_frustumRadiusVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 _lightProjectionViewMatrix </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ortho</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumRadius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumRadius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumRadius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumRadius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">            0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            _frustumSliceCenter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _frustumRadius</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        )</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _lightView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        lightViewProjectionMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_lightProjectionViewMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        splitDepths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_depth </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">splitIdx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.7f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadowMappingLightViewProjectionMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightViewProjectionMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadowRenderingLightViewProjectionsUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightViewProjectionMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadowRenderingSplitsUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">splitDepths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Then geometry shader would be:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">triangles</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> this shader will be emitting data to 4 shadow map layers as per 4 frustum splits;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> each triangle fed into this geometry shader will be projected into each shadow map layer;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> hence this shader will emit 4 layers * 3 vertices (per each input primitive / geometry) = 12 vertices;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> note how the input vertices are in the world space, so we need to project them to the clip space in here</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">*/</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">triangle_strip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> max_vertices </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// out int gl_Layer;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightViewProjectionMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // as per 4 frustum splits</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> split </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> split </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">split</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // input primitive index</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_in</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // in a 3D texture, which layer do we project our input primitive to</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gl_Layer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> split</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // project an input primitive using the corresponding projection matrix from the uniform</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightViewProjectionMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">split</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_in</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            EmitVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        EndPrimitive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The rendering stage would use the projection matrices too. So setting up the rendering shader:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingFragmentShaderSource </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sourceFromFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/shadow-rendering.frag"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingFragmentShaderTemplate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applyGlobalReplacements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingFragmentShaderSource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingFragmentShader </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FRAGMENT_SHADER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingFragmentShaderTemplate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingFragmentShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">compile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "[ERROR] Can not compile chicken fragment shader"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Program</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowRenderingVertexShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingFragmentShader</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingModelTransformationUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"model"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingViewTransformationUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"view"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProjectionTransformationUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projection"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingLightPositionUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightPosition"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingLightColorUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightColor"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingCameraPositionUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"cameraPosition"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingLightViewProjectionsUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightViewProjections"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingSplitsUniform </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowRenderingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getUniform</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"splits"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // distance from camera to zFar, e.g. (far - cameraPosition.z) * splitFraction</span></span></code>

And finally, the fragment shader for the final rendering stage:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 viewPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightViewProjections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2DArray</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMaps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraViewDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">viewPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraViewDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> splits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            vec4 fragmentPositionInLightSpace </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightViewProjections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            vec3 shadowPos1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            vec3 shadowMapCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowPos1 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMaps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.05</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.005</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.25</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ambient</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 ambient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.3</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // diffuse</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // specular</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 viewDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 halfwayDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> viewDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> halfwayDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 64.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 specular </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // calculate shadow</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lighting </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specular</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ambient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lighting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Note how now the shadow calculation function makes use of the projection matrices, so instead of rendering the scene multiple times again, we simply pick the shadow data from a corresponding shadow map buffer.

Anti-aliasing

You might have noticed that rendering scene from the framebuffer results in most lines looking like stairs, with very distinct hard edges around every shape. This is most obvious during the deferred rendering.

In order to prevent (or rather somewhat mitigate) this issue, the technique called "anti-aliasing" is used. It softens the pixels around those hard edges so they gradually change color instead of hard jump.

Multi-sampled anti-aliasing (MSAA)

I have never understood the concept of multi-resolution pyramid (even when working on my second M.Sc. thesis) until I got myself into all this OpenGL stuff. The way you can soften the rapid change of a color in neighbour pixels is to upscale the image image few times and then downscale it back. This way you will loose a lot of detail, getting an average color value for each scaling level. OpenGL actually comes bundled with the multi-sampled rendering feature - when you create a framebuffer you can specify the number of samples for texture.

But you can implement one by yourself, explicitly, using one rather simple shader program and a deferred rendering technique.

First rendering pass would be rendering a scene to a frame buffer. The last (or second, in this overly-simplified example) rendering pass would run on top of that frame buffer and compute the new one using the simple shader program:

vertex shader for the MSAA last rendering pass:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

fragment shader for the last rendering pass:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">vec4</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> msaa</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sampler2D </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec2 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> )</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 resolution </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 singleSample </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> resolution</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> resolution</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 acc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">uv </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">uv </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">uv </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">uv </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // vec4 color = pow(acc, vec4(1.0 / 2.2));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> msaa</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Fast-approximation anti-aliasing (FXAA)

Multi-sampled rendering is fine, but usually it comes at a cost of higher memory consumption - for each multi-sampled texture you have to allocate memory. The more multi-sampled textures you have - the more memory your application consumes.

Fast approximation works at constant time and memory and thus is one of the most popular anti-aliasing algorithms used. It is also quite easy to implement, which makes it all more appealing.

The algorithm actually detects the edges on the image and then blends the colors in the direction perpendicular to the edge.

That sounds easy on paper, but how does it actually detect the edges? The algorithm calculates the luminance of the pixels surrounding a given central pixel by calculating a dot product of each pixel' color and a constant luminance vector. It then compares the luminance in two directions vertically and two directions horizontally to find the edge' direction.

The only substantial difference in the code for FXAA is in the fragment shader for the last rendering pass:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#define</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FXAA_SPAN_MAX</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16.0</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#define</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FXAA_REDUCE_MUL</span><span style="color:#7C7F93;--shiki-dark:#949CBB">   (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FXAA_SPAN_MAX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#define</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FXAA_REDUCE_MIN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">   (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 128.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#define</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FXAA_SUBPIX_SHIFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">vec4</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fxaa</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sampler2D </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec2 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">uv2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> )</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 rcpFrame </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 uv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv2 </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rcpFrame </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FXAA_SUBPIX_SHIFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rgbNW </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rgbNE </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zw </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rcpFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rgbSW </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zw </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rcpFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rgbSE </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zw </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rcpFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 texColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rgbM  </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> texColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 luma </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.299</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.587</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.114</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaNW </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbNW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luma</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaNE </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbNE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luma</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSW </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbSW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luma</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSE </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luma</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaM  </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbM</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  luma</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaMin </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaM</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaNW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaNE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaSW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaMax </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaM</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaNW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaNE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaSW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaNW </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaNE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaSW </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">  ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaNW </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaNE </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dirReduce </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaNW </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaNE </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSW </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.25</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FXAA_REDUCE_MUL</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FXAA_REDUCE_MIN</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rcpDirMin </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">abs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> abs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dirReduce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dir </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> min</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FXAA_SPAN_MAX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  FXAA_SPAN_MAX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FXAA_SPAN_MAX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FXAA_SPAN_MAX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            dir </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rcpDirMin</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        )</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    )</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rcpFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rgbA </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dir </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dir </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rgbB </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgbA </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dir </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dir </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaB </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luma</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaB </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaMin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lumaB </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lumaMax</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> texColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgbB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> texColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fxaa</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Screen-space ambient occlusion (SSAO)

As you might know, rendering big and complex scenes is expensive in both time, memory and computational resources. It is not always desirable or even possible to render all effects like reflections and shadows for each and every polygon of the scene.

To address this issue, techniques like ambient occlusion (specifically, screen-space ambient occlusion, in that they only work in screen space, combined with deferred rendering, as a post-processing step) exist. This technique in particular allows simulating the shadow cast by the objects by darkening the pixels which are occluded by other objects from the perspective of light.

Sounds very much like shadow mapping, doesn't it? But the big difference here is that in shadow mapping you need to render an entire scene from the perspective of each light source. Even if you trim the scene to only the objects visible by the light (which is a quite nice optimization, but for the most part it is also expensive), you will still have to render every polygon.

In contrast, ambient occlusion is calculated for a fixed number of samples around a given pixel. On top of that, the pixels we analyze are only in screen space. On top of that, we do not need to render all the geometry around a given pixel - we re-use the position information rendered as one of the attributes in first pass of a deferred rendering. To reduce the cost of this algorithm even further, you do not need to render anything from the light perspective - you just calculate the sample rays of light for each light, knowing its position and direction.

You will need to store the position of each fragment in camera space (yes, camera space, not light space). Then, for each pixel, you iterate each source of light to calculate the direction of light and samples for a given pixel' position in camera space. You assume you have a sphere of a given constant radius around the pixel' position and you generate a certain constant number of random samples within that sphere. Since the samples are also in the camera space, you can use these positions as-is. Given the information about positions of neighbour pixels in camera space, you then compare those positions to the samples within the sphere - if the sample's position is further from the camera than the neighbour pixel's position - this sample is occluded by some polygon. You then calculate the ratio of occluded samples to the non-occluded ones and based on that give the original pixel its shadow value.

Read more:

Setting up the initial render pass framebuffer is a bit tricky - you will need multiple attachments for each of the data component:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentPositionTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB32F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentNormalTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB32F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentAlbedoTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_UNSIGNED_BYTE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentDepthTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredRenderingFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_ATTACHMENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// tell framebuffer it actually needs to render to **BOTH** textures, but does not have to output anywhere (last NONE argument, iirc)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDrawBuffers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NONE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

You will also need two buffers for blur:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryTexture1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_UNSIGNED_BYTE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDrawBuffers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NONE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryTexture2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_UNSIGNED_BYTE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryFramebuffer2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDrawBuffers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NONE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

And the random data (vector offsets) for the SSAO algorithm, which we will generate in the application and store in a small texture:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">uniform_real_distribution</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> randomFloats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // random floats between [0.0, 1.0]</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">default_random_engine generator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoKernelSamples </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 64</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoKernel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoKernelSamples</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        randomFloats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">generator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        randomFloats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">generator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        randomFloats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">generator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    sample </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    sample </span><span style="color:#179299;--shiki-dark:#81C8BE">*=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> randomFloats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">generator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernelSamples</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // lerp(a, b, f) = a + f * (b - a);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // scale = lerp(0.1f, 1.0f, scale * scale);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    scale </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1f</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scale </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    sample </span><span style="color:#179299;--shiki-dark:#81C8BE">*=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoKernel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoNoise</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">noise</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        randomFloats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">generator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        randomFloats</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">generator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0.0f</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoNoise</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">noise</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoNoiseTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NEAREST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NEAREST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_REPEAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_REPEAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB32F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoise</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoKernelTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_1D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NEAREST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NEAREST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image1D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA16F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernelSamples</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

With the rendering itself, there are no tricks - you have three passes.

On the first pass you bind the deferred rendering buffer (with a few attachments, that is) and render scene as normal. The textures attached to the deferred rendering buffer will be populated with the data.

This data is then used on the second rendering pass to calculate the dark edges (amboent occlusion) on the frame rendered (aka in the screen space) and blur them.

On the last rendering pass you combine the framebuffers to obtain the final image:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// first render pass - prepare for deferred rendering by rendering to the entire scene to a deferred rendering framebuffer's attachments</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingPrePassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // render scene</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingPrePassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// second render pass - calculate &#x26; blur the ambient occlusion</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glViewport</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glClearColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    glClear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GL_DEPTH_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"positionTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"normalTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"albedoTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ssaoNoiseTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ssaoKernelTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"cameraPosition"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projection"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraProjection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"view"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ssaoProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // blur</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_READ_FRAMEBUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DRAW_FRAMEBUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ClearBufferMask</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NEAREST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // same as</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // glReadBuffer(GL_COLOR_ATTACHMENT0);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // glDrawBuffer(GL_COLOR_ATTACHMENT0);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // glBlitFramebuffer(0, 0, window.getSize().x, window.getSize().y, 0, 0, window.getSize().x, window.getSize().y, static_cast&#x3C;gl::ClearBufferMask>(GL_COLOR_BUFFER_BIT), static_cast&#x3C;gl::GLenum>(GL_NEAREST));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    blurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> blurPasses </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // for the initial blur pass, use the texture from the bloomFramebuffer as an input</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // we do not need anything extra here, since the bloomBlurFramebuffer2 (which we read from) will already contain the data from the bloomBrightnessTexture</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    blurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"blurInput"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> blurPasses</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // bind one framebuffer to write blur results to and bind the texture from another framebuffer to read input data from (for this blur stage)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // bind the new target framebuffer to write blur results to</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // bind the texture from the previous blur pass to read input data for this stage from</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            temporaryTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // tell shader that we want to use horizontal blur</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            blurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"isHorizontalBlur"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // bind the new target framebuffer to write blur results to</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // bind the texture from the previous blur pass to read input data for this stage from</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // tell shader that we want to use vertical blur</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            blurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"isHorizontalBlur"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // render quad with the texture from the active texture</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // unbind the active framebuffer</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            temporaryFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // unbind the active texture</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            temporaryTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            temporaryFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    blurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// third render pass - merge textures from the deferred rendering pre-pass into a final frame</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glViewport</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glClearColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    glClear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GL_DEPTH_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindBase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"positionTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"normalTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"albedoTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ssaoTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"cameraPosition"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projection"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraProjection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"view"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The fragment shader for the first render pass:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsAlbedo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsNormal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normalMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        fsNormal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsAlbedo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Note how it has three output vectors , each of which will be bound to the corresponding framebuffer attachment.

The fragment shader for SSAO (second render pass) :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler1D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.025</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 screenSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 noiseSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kernelSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 noiseScale </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> screenSize </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> noiseSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 randomVec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> noiseScale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 tangent </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">randomVec </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">randomVec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 bitangent </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> cross</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tangent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mat3 TBN </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mat3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tangent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bitangent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kernelSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec3 samplePosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> TBN </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">samplePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            samplePosition </span><span style="color:#179299;--shiki-dark:#81C8BE">*=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        samplePosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> samplePosition </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec4 offsetUV </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">samplePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        offsetUV</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> offsetUV</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        offsetUV</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> offsetUV</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec4 offsetPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> offsetUV</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rangeCheck </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> smoothstep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> abs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> offsetPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">samplePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> offsetPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rangeCheck</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kernelSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">occlusion</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The blur fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isHorizontalBlur</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.2270270270</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1945945946</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1216216216</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0540540541</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0162162162</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isHorizontalBlur</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The final render pass fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PointLight</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // float farPlane;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // mat4 projectionViewMatrices[6];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer PointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    PointLight pointLight</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> albedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ssaoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_constant </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_linear </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.09</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_quadratic </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.032</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 albedoColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">albedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 viewDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ambientOcclusion </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ssaoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 lighting </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> albedoColor </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.3</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ambientOcclusion</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        PointLight light </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec3 lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">light</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">position </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDistance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">light</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">position </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attenuation_constant </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attenuation_linear </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDistance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attenuation_quadratic </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDistance </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDistance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec4 diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> albedoColor </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> light</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        lighting </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lighting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Since all of the rendering is happening in passes on the frame buffers, the vertex shaders are very simple - just passing the parameters through to the next stage.

Horizon-based ambient occlusion (HBAO)

Screen-space ambient occlusion algorithm (aka SSAO) is fine, but it can use even further improvement. Instead of calculating random samples inside imaginary sphere, you can be a little smarter about those samples and only generate them in a hemisphere, oriented towards the camera. Then, instead of checking the camera-space positions of samples and pixels, you can use the "horizon" of a current pixel and calculate the "horizion" for each of the samples. You can then use the angle difference between those two "horizons" to see if pixels are potentially occluded by some other polygon.

This technique gives better results for corners and edges than conventional SSAO technique.

Read more:

The difference between SSAO and HBAO implementations lays in literally one fragment shader, calculating the ambient occlusion values (the second pass, from the SSAO paragraph) :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hbaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler1D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hbaoKernelTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PI </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NUM_SAMPLE_DIRECTIONS </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NUM_SAMPLE_STEPS </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> INTENSITY </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 screenSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 noiseSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hbaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 noiseScale </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> screenSize </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> noiseSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stepPixels </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NUM_SAMPLE_STEPS </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> alpha </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PI </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NUM_SAMPLE_DIRECTIONS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NUM_SAMPLE_DIRECTIONS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angle </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> alpha </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec4 random </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hbaoNoiseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> noiseScale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // vec2 dir = vec2(cos(angle), sin(angle));</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // vec2 cosSin = random.xy;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // vec2 direction = vec2(dir.x * cosSin.x - dir.y * cosSin.y, dir.x * cosSin.y + dir.y * cosSin.x);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // vec2 direction = rotateDirection(vec2(cos(angle), sin(angle)), random.xy);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec2 direction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">angle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> random</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">angle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> random</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> cos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">angle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> random</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">angle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> random</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rayPixels </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> random</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stepPixels </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NUM_SAMPLE_STEPS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            vec2 sampleUV </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> round</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rayPixels </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> direction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> screenSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            vec3 samplePosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sampleUV</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            rayPixels </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stepPixels</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            vec3 sampleDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> samplePosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sampleDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sampleDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sampleDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sqrt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> clamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v2 </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> clamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v1 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">radius </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">*=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> INTENSITY </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NUM_SAMPLE_DIRECTIONS </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NUM_SAMPLE_STEPS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    occlusion </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> clamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">occlusion</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">occlusion</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Volumetric lighting

Have you ever seen those beautiful rays of light passing through the clouds and becoming actually visible rays ? There are lots of these in games too. They are also known as "god rays". They are actually tiny particles (presumingly dust) hanging in the air and reflecting the light.

The technique which allows to achieve such an effect (and tons of others) is called "raymarching".

The idea is that you store the pixels' depth and position information in both light space and camera space and then you cast an imaginary ray from the camera towards each pixel rendered. You then split this ray into a constant number of parts and project the resulting points into light space. You then compare the position of the point on the ray in light space to the depth value stored in the light space, and if the depth value stored is greater than the position on the ray - the point on the ray is visible from the perspective of a light, so you make the pixel on the screen a bit brighter. The more parts of the ray are visible by the light - the brighter the pixel will be.

Read more:

The implementation for this technique is actually pretty straightforward: this is a two-pass deferred rendering application.

First, you set up a framebuffer with multiple attachments, for each of the scene parameters:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentPositionTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB32F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentNormalTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB32F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentAlbedoTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_UNSIGNED_BYTE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentLightSpacePositionTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentLightSpacePositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentLightSpacePositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentLightSpacePositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB32F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentDepthTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredRenderingFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentLightSpacePositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_ATTACHMENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// tell framebuffer it actually needs to render to **BOTH** textures, but does not have to output anywhere (last NONE argument, iirc)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDrawBuffers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NONE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Then, you render scene to that framebuffer:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingPrePassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// render scene</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingPrePassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deferredRenderingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

The vertex shader for this pass is:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// layout (location = 3) in vec3 vertexTangent;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// layout (location = 4) in vec3 vertexBitangent;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightSpaceCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> transpose</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inverse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mat3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 lightSpaceCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightSpaceCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And the fragment shader is:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightSpaceCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsAlbedo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsLightSpaceCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsNormal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normalMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        fsNormal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsNormal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsAlbedo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fsLightSpaceCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightSpaceCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

In the final render pass you just combine the textures of the previous render pass(-es) into the final frame:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// final render pass - merge textures from the deferred rendering pre-pass into a final frame</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glViewport</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glClearColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLfloat</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    glClear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GL_DEPTH_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentLightSpacePositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindBase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"positionTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"normalTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"albedoTexture"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightSpaceCoord"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deferredFragmentLightSpacePositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"shadowMap"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"cameraPosition"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projection"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraProjection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"view"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lightSpaceMatrix"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sunDirection"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sunColor"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentPositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeNonResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentNormalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeNonResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentAlbedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeNonResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredFragmentLightSpacePositionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeNonResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">textureHandle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">makeNonResident</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    deferredRenderingFinalPassProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Using the fragment shader, which increases the brightness of the pixels based on the information from the light projection buffer. This is done using counting (or the "accumulating") the number of intersections of the ray from the viewing position towards the light source (by checking the light projection buffer - the position of each pixel in the light space) :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">460</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#extension GL_ARB_bindless_texture : require</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PointLight</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // float farPlane;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // mat4 projectionViewMatrices[6];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer PointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    PointLight pointLight</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bindless_sampler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bindless_sampler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bindless_sampler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> albedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bindless_sampler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bindless_sampler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sunDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sunColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_constant </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_linear </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.09</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_quadratic </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.032</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NB_STEPS </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> G_SCATTERING </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.858</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#define</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> M_PI</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.1415926535897932384626433832795</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">positionTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normalTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 albedoColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">albedoTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 viewDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 startPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 endRayPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rayVector </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> endRayPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> startPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rayLength </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rayVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 rayDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rayVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stepLength </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rayLength </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NB_STEPS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 raymarchingStep </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rayDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stepLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 currentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> startPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 accumFog </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NB_STEPS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // basically perform shadow mapping</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec4 worldInLightSpace </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">currentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        worldInLightSpace </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worldInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec2 lightSpaceTextureCoord1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">worldInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // [-1..1] -> [0..1]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapValue1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceTextureCoord1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapValue1 </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worldInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // Mie scaterring approximated with Henyey-Greenstein phase function</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDotView </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rayDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sunDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scattering </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> G_SCATTERING </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> G_SCATTERING</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            scattering </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> M_PI </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> G_SCATTERING </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> G_SCATTERING </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.0f</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> G_SCATTERING</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDotView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.5f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            accumFog </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scattering </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sunColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        currentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> raymarchingStep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    accumFog </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NB_STEPS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // fade rays away</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // accumFog *= currentPosition / NB_STEPS);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // lighting *= accumFog;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 fragmentPositionInLightSpace1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightSpaceMatrix </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentPositionInLightSpace1 </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPositionInLightSpace1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 shadowMapCoord1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPositionInLightSpace1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // vec3 fragmentPositionInLightSpace2 = texture(lightSpaceCoord, fsIn.textureCoord).xyz;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // vec2 shadowMapCoord2 = fragmentPositionInLightSpace2.xy;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPositionInLightSpace1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowFactor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shadowFactor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">albedoColor </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowFactor </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">accumFog </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Common rendering techniques

There are few simpler effects and techniques, which are more widely known (in that more tutorials on the Internet discuss these to some degree), but I feel like describing them as well.

Bloom

Bloom is a relatively simple effect, but it looks really nice.

The idea is that you render the scene to a framebuffer, storing the light emitting value per pixel. You then blur the resulting image (using Gaussian blur, for instance) and blend the original scene image with the blurred one.

The only complex part here is Gaussian blur.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> antiAliasingSamples </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomColorTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D_MULTISAMPLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomColorTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2DMultisample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    antiAliasingSamples</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB16F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLboolean</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBrightnessTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D_MULTISAMPLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBrightnessTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2DMultisample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    antiAliasingSamples</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB16F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLboolean</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Renderbuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">renderBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">storageMultisample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">antiAliasingSamples</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH24_STENCIL8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomColorTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBrightnessTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachRenderBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_STENCIL_ATTACHMENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// tell framebuffer it actually needs to render to **BOTH** textures, but does not have to output anywhere (last NONE argument, iirc)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDrawBuffers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NONE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryOutputTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB16F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryOutputFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBlurTexture1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB16F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBlurFramebuffer1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurFramebuffer1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurFramebuffer1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBlurTexture2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">image2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGB16F</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBlurFramebuffer2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span></code>

With all that preparatory work, the rendering is a multi-step (multi-pass) process - first pass is to render scene to the bloomFramebuffer , filling the bloomColorTexture and bloomBrightnessTexture :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// render scene</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

The shader for the first rendering pass is only different in fragment phase:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> brightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specularMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_constant </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_linear </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.09</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_quadratic </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.032</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 shadowMapCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPositionInLightSpace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.05</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.005</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // PCF</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 texelSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pcfDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xy </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> texelSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pcfDepth  </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">/=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ambient</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 ambient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.3</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // diffuse</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // specular</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 viewDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 halfwayDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> viewDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> halfwayDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 64.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 specular </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // attenuation</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attenuation_constant </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_linear </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_quadratic </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // calculate shadow; this represents a global directional light, like Sun</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // these are the multipliers from different light maps (read from corresponding textures)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specularCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">specularMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">emissionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lighting </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionCoefficient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">specular </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specularCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ambient </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">emissionColor </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> brightness </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lighting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.2126</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.7152</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0722</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">brightness </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        brightColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lighting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        brightColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lighting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The second scene rendering blurs the framebuffer's data by rendering the texture to a quad (that is, a rectangle with same dimensions as the screen; this makes a deferred rendering) and making each pixel an average of the neighbour pixels from the previous step:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// copy data from the multisampled framebuffer to non-multisampled textures</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// since the bloomFramebuffer has two color attachments, we need to blit twice</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// but doing so removes the need in some additional conditions when running the blur</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_READ_FRAMEBUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DRAW_FRAMEBUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    temporaryOutputFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ClearBufferMask</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NEAREST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// same as</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// glReadBuffer(GL_COLOR_ATTACHMENT0);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// glDrawBuffer(GL_COLOR_ATTACHMENT0);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// glBlitFramebuffer(0, 0, window.getSize().x, window.getSize().y, 0, 0, window.getSize().x, window.getSize().y, static_cast&#x3C;gl::ClearBufferMask>(GL_COLOR_BUFFER_BIT), static_cast&#x3C;gl::GLenum>(GL_NEAREST));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_READ_FRAMEBUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DRAW_FRAMEBUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    bloomBlurFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">window</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ClearBufferMask</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_BUFFER_BIT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NEAREST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// third pass - blur the data stored in the bloom framebuffer with two-pass Gauss blur</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> blurPasses </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// for the initial blur pass, use the texture from the bloomFramebuffer as an input</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// we do not need anything extra here, since the bloomBlurFramebuffer2 (which we read from) will already contain the data from the bloomBrightnessTexture</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"blurInput"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> blurPasses</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // bind one framebuffer to write blur results to and bind the texture from another framebuffer to read input data from (for this blur stage)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // bind the new target framebuffer to write blur results to</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurFramebuffer1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // bind the texture from the previous blur pass to read input data for this stage from</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // tell shader that we want to use horizontal blur</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"isHorizontalBlur"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // bind the new target framebuffer to write blur results to</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // bind the texture from the previous blur pass to read input data for this stage from</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // tell shader that we want to use vertical blur</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"isHorizontalBlur"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // render quad with the texture from the active texture</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // unbind the active framebuffer</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurFramebuffer1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // unbind the active texture</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurFramebuffer2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        bloomBlurTexture1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

The fragment shader for blur render pass:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isHorizontalBlur</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.2270270270</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1945945946</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1216216216</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0540540541</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0162162162</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isHorizontalBlur</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

As with most cases described in this blog, the vertex shader for both stages is just the same old projection, nothing fancy:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Except there is no need to project anything when rendering to the quad, so the difference is only in the last line for the blur shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Now, the last rendering pass is quite simple, but that's where the magic becomes reality: we mix the original picture, rendered to the temporaryOutputTexture (first render pass) with the blurred bright pixels from bloomBlurTexture2 (the second render pass) to get the glow effect:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomOutputProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// here we use our temporary non-multisampled texture as one of the inputs for merge bloom effect stages, since OUR shader would only work with one sample layer</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomOutputProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"colorOutput"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomOutputProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"blurOutput"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">quadModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">temporaryOutputTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomBlurTexture2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbindActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bloomOutputProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isHorizontalBlur</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.2270270270</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1945945946</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.1216216216</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0540540541</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0162162162</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> textureSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isHorizontalBlur</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            result </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">blurInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoord </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> textureOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> weight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Vertex shader is same deferred rendering vertex shader - without any projection going on.

Particle systems

Particle simulation is not really a technique in itself - it is a very big topic (how you design it from the code perspective, how do you simulate particles optimally - concurrent programming, SIMD, calculations on the GPU, etc.). But the way you render bunch of particles could be qualified as a rendering technique. It is mostly about instanced rendering.

The standard implementations include calculating every particle's params (position, rotation, texture animation frame etc.) on CPU and passing that data to the GPU to be rendered. More interesting approach is to do all the calculations on the GPU itself, only passing a handful of parameters from CPU, like the number of particles and their origin - essentially, the particle emitter parameters and then using the computing shader to do the rest.

Read more:

Skybox

Sky can really add atmosphere to your game. Rendering it might be as simple as rendering an inverted cube with texture on the insides of its faces and moving it along with the camera (or rather rendering it in camera space, not world space).

The skybox can use normal textures or it could use cubemaps - literally just a cube with textures on each of its six sides. Cubemaps allow you to calculate the texture coordinates by only having a vector from the center of the cube in the direction of view.

Read more:

In order to implement skybox, one first needs a cubemap texture:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Image m_top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_bottom</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_front</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_back</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// load textures with SFML</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> sf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Image</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skyboxTextures</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_NEGATIVE_X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_left </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_top </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_NEGATIVE_Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_bottom </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_back </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_NEGATIVE_Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_front </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skyboxTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLint</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_EDGE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kv </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skyboxTextures</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> target </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    auto</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> image </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_Y </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> target </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_NEGATIVE_Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        image</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flipVertically</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        image</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flipHorizontally</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glTexImage2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">image</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLsizei</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">image</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_UNSIGNED_BYTE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        reinterpret_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ::GLvoid</span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">image</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPixelsPtr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

In my sample I manually create a box mesh with inverted normals:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normals</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">for_each</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">](</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">vec3</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 13</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 17</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 19</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 21</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 22</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    23</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 22</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec2</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uvs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.333333f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.333333f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.333333f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.333333f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.333333f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.333333f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.340000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.340000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.666666f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.000000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.500000f</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// use AbstractMesh to render this</span></span></code>

The only difference in rendering skybox is the use of samplerCube for texture in the fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> samplerCube</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cubeMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cubeMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

In vertex shader, however, the textureCoords variable is set using the camera view matrix passed as a uniform variable:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">410</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexUV</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 pos </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> //.xyww;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And passing the matrix to the uniform variable in the application (thanks globjects for a beautiful API) :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxRenderingProjectionTransformationUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraProjection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skyboxRenderingViewTransformationUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mat4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mat3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraView</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span></code>

Point lighting

When people are talking about point light sources, they usually mean light attenuation (light intensity fading with the distance from the light source) and object shading calculation for each light source around a given polygon (you calculate the Blinn-Phong shading considering each light source and light attenuation).

A bit more interesting here is the shadow casting technique. Instead of rendering shadow map as a simple 2D texture, you will need to utilize the cubemap, rendering an entire scene for each light source six times. But bear in mind: this is a very calculation-intensive technique, so refrain from doing so on the large landscapes. Alternatively, you should limit the light sources to the ones that are visible (or whose shadows are visible) in the camera space.

The implementation is quite interesting - it is an inversion of a cubemap rendering technique - instead of sampling the cubemap texture we now render to the cubemap texture. Initializing this texture:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMapTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_BORDER_COLOR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glTexImage2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_X </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

This texture will be attached to a framebuffer:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMappingFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_ATTACHMENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointShadowMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Since the cubemap is effectively six different textures, we will need to render to all of them, using different light projection matrices. We can somewhat optimize this by using geometry shader. Passing the matrices could be optimized using the SSBO:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> alignas(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightDataBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Buffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// calculate the 6 light projection matrices</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">perspective</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">radians</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">90.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMapSize </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightProjectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    pointLightProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PointLightData pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLightProjectionViewMatrices </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DYNAMIC_COPY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span></code>

Then, on each frame, bind the SSBO and render scene to a framebuffer with cubemap texture attached to it:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// bind the buffer on each frame</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bindBase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// render frame</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLightDataBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_SHADER_STORAGE_BUFFER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointShadowMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

For shadow mapping pass, the shaders are as following:

geometry shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">triangles</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// we emit 6 triangles for one input triangle - to be written to 6 textures of the cubemap</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">triangle_strip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> max_vertices </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PointLight</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">   vec3 lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">   float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">   mat4 projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer pointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">   PointLight pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gl_Layer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertex </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_in</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            EmitVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        EndPrimitive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PointLight</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mat4 projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer pointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    PointLight pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_FragDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And for the final render pass (sampling the shadow cubemap) :

vertex shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PointLight</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mat4 projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer pointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    PointLight pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xyz </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_FragDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> samplerCube</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specularMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PointLight</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mat4 projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std430</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binding </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buffer pointLightData</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    PointLight pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// TODO: make these params uniforms</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// uniform vec3 ambientColor;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// uniform vec3 diffuseColor;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// uniform float materialSpecular;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_constant </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_linear </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.09</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_quadratic </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.032</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pcfSamples </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pcfSampleOffsetDirections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pcfSamples</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3[]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">   vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">   vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">   vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">   vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">   vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec3 </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentToLight </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadowMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentToLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentToLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // PCF</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*float shadow = 0.0;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    float viewDistance = length(fsIn.fragmentPosition - cameraPosition);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    float diskRadius = (1.0 + (viewDistance / farPlane)) / 50.0;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    for (int i = 0; i &#x3C; pcfSamples; ++i)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        float closestDepth = texture(shadowMap, fragmentToLight + pcfSampleOffsetDirections[i] * diskRadius).r * farPlane;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        if (thisDepth - bias &#x3C; closestDepth)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            shadow += 1.0;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    shadow /= float(pcfSamples);*/</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bias</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> occluderDepth </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rgb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ambient</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 ambient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.3</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // diffuse</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 diffuse </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diff </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // specular</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 viewDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cameraPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 halfwayDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> viewDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> halfwayDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 64.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 specular </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // attenuation</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightRadius </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pointLight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lightPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lightRadius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attenuation_constant </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_linear </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attenuation_quadratic </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">distance </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> distance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // calculate shadow; this represents a global directional light, like Sun</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> shadowCalculation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // these are the multipliers from different light maps (read from corresponding textures)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specularCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">specularMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">emissionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // vec3 lighting = ((shadow * ((diffuse * attenuation) + (specular * specularCoefficient * attenuation))) + (ambient * attenuation)) * color + (emissionColor * emissionCoefficient);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 lighting </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">specular </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> specularCoefficient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ambient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">emissionColor </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> emissionCoefficient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lighting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Note how the shadow map is samplerCube and sampling it is using the vec3 instead of vec2 as with planar (2D) textures. Also note how lighting has something called "attenuation" now - this is the fading-out factor - the further the pixel is from the light source - the more bleak the lighting effect would be.

Reflections

Reflections on the water surface are relatively simple to implement - for each pixel you calculate the direction to the camera upside-down (simply create a new view matrix with "up" vector pointing down) and then use the GLSL function reflect() to calculate the reflected vector. You then render take the color at the reflected position and add it (multiplied by some transparency factor) to the original pixel' color.

The concept of cubemaps is not only useful for skyboxes, but could also be used to calculate reflections on the objects. For each reflective object you render the scene from its position to the cubemap texture (so you will have to render the scene six times, which is huge overhead in itself) and when rendering the object, you reflect the camera view vector (vector from the pixel in world space to camera position) and sample the cubemap with that vector. You then add the sampled color to the source pixel color to receive a nice reflective surface effect.

This technique is very similar to both point light shadow mapping and skybox rendering combined.

We will need the cubemap texture to render to:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionMapTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_BORDER_COLOR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionMapSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2048</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glTexImage2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_X </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_RGBA8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        reflectionMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        reflectionMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_RGBA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_UNSIGNED_INT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

And on top of that, for things to not look mangled, we will need a depth texture. Which also has to be a cubemap:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionMapDepthTexture </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MIN_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_MAG_FILTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_LINEAR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_WRAP_R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_CLAMP_TO_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setParameter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_BORDER_COLOR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">glTexImage2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        static_cast&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">::GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_TEXTURE_CUBE_MAP_POSITIVE_X </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        reflectionMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        reflectionMapSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_DEPTH_COMPONENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        GL_FLOAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

They both are then attached to a framebuffer:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionMappingFramebuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">globjects</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Framebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionMapTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attachTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_DEPTH_ATTACHMENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionMapDepthTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// tell framebuffer it actually needs to render to **BOTH** textures, but does not have to output anywhere (last NONE argument, iirc)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDrawBuffers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ </span><span style="color:#179299;--shiki-dark:#81C8BE">static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_COLOR_ATTACHMENT0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#179299;--shiki-dark:#81C8BE"> static_cast&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GLenum</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GL_NONE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">printStatus</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Then, we have to render scene... well, 6 times - once for each side of the reflection cubemap:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// this is a cubemap, hence aspect ratio **must** be 1:1</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mat4 reflectionProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">perspective</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">radians</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">90.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nearPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> farPlane</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// TODO: technically, this should be calculated as AABB / 2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionOffset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.05f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projectionViewMatrices[0]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projectionViewMatrices[1]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projectionViewMatrices[2]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projectionViewMatrices[3]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projectionViewMatrices[4]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setUniform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"projectionViewMatrices[5]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionProjection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionOffset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectiveModelPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> glm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">use</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// render scene EXCEPT the mirror object</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingFramebuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unbind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMappingProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">release</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

For this we use geometry shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">triangles</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// we emit 6 triangles for one input triangle - to be written to 6 textures of the cubemap</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">triangle_strip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> max_vertices </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gsIn</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// out vec4 fragmentPosition;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gl_Layer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertex </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projectionViewMatrices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">face</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            EmitVertex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        EndPrimitive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Vertex shader for reflection mapping:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> modelTransformation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> modelTransformation </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modelTransformation </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And fragment shader:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // TODO: add lighting component here</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_FragColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Note how the output is a 4-component vector instead of a regular 3-component one.

When rendering the reflective object on the final render pass, we sample the reflection cubemap texture and use the reflect function in vertex shader to calculate the sampling vector from the camera view vector:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 reflectedDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">out</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gl_PerVertex </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 gl_Position</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexTextureCoord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectedDirection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> reflect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">normalize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vsOut</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fragmentPosition </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertexNormal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gl_Position </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> projection </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> vec4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vertexPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

In the fragment shader we then combine the color sampled from reflection texture and the object' own (albedo) color:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#version </span><span style="color:#FE640B;--shiki-dark:#EF9F76">430</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">layout</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">location </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fragmentColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VS_OUT</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 fragmentPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec2 textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec3 reflectedDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> samplerCube</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sampler2D</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// uniform vec3 lightColor;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> vec3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cameraPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">uniform</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> mat4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 reflectionColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectionMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">reflectedDirection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec4 albedoColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> texture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">diffuseTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fsIn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fragmentColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">albedoColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reflectionColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Message compression formats in a web application urn:uuid:5332cc68-0918-5d69-a885-90f3d1ddeb65 2022-10-25T00:00:00Z 2022-10-25T00:00:00Z

I have seen quite a few web applications which are passing heaps of data between client and server. Pretty much all of them use JSON for that purpose. And whilst that solves the business problem, some of those applications aim to provide nearly real-time user experience, and that's where the issues arise.

With the rise of web sockets, RTC and HTTP2 tech, the data transfer speed issues might be not so noticeable, but the more data app tries to transfer, the more pressing the matter gets. This issue also becomes more apparent on the server side - server has to process a lot more data in a request thread.

At The Trade Desk I have observed an approach, where we are transferring a list of strings (later we converted them to integers to widen the bandwidth) between high-loaded services (think 15 million requests per second with a hard time bound on request processing of 100 milliseconds).

I thought this is a cool concept, worth exploring deeper. For this matter, I have searched the Internet for similar approaches.

One of the readings was an article on the russian resource about speeding up a web application by switching from HTTP1 to HTTP2, utilizing various data compression formats: for static assets - WEBP, AVIF and progressive JPEG; for general data - various stream compression algorithms - GZIP, Brotli and ZSTD; alongside with different data serialization formats - MessagePack.

I decided to expand my search in the direction of serialization formats. In this article I compare few of those and focus on their performance in serializing different kinds of data (lists, nested objects, integers and strings, large and small datasets) and the serialization & deserialization performance in browser and the compression rates.

The formats covered are:

One of the optimizations we have achieved at The Trade Desk was 7 times reduction in data size by switching from string IDs to integer values. Think "something-else" we used to operate everywhere was assigned an integer ID of 4092 . Now that int is 4 bytes long, whereas the string value is 14 bytes long. That is more than 3x reduction in size, but you have to still store the mapping somewhere, which we already did (in our case).

But the overall idea is worth researching too - how much compression each format provides when working with long lists of strings and long lists of ints.

To make the thing more interesting, I came up with few various data types to be messed around:

  • a simple object Pet { name: string, kind: enum Kind { CAT, DOG } }
  • an object with an array of string identifiers StringIdsResource { ids: string[] }
  • an object with an array of integer identifiers StringIdsResource { ids: int[] }

As mentioned before, the metrics I'm going to be focusing on are:

  • encoding & decoding performance in browser environment
  • encoded message length (raw, as UTF-8 string and base-64 encoded UTF-8 string)
  • amount of runtime (bundled code) required to work with the format

To make it quick and easy, here's the summary (time measured in browser, on a nested object with a list of 1000 children of various data types) :

Serializer Encoding time Decoding time Encoded data size (byte array) Compression Encoded data size (base-64 utf-8 encoded) Bundle size
Avro 12ms 4ms 30003 77.16% 40004 111.7kb
BSON 10ms 11ms 98912 24.71% 131884 98.0kb
CBOR 3ms 4ms 89017 32.24% 118692 30.1kb
MessagePack 3ms 3ms 89017 32.24% 118692 27.7kb
Protobuf 13ms 3ms 38000 71.07% 50668 76.6kb
Protobuf, compiled 6ms 1ms 38000 71.07% 50668 30.0kb
Flatbuffers 9ms 3ms 32052 75.60% 42736 3.1kb
Thrift (binary) 42ms 6ms 45009 65.74% 60012 109.7kb
Thrift (compact) 33ms 11ms 36005 72.59% 48008 109.7kb

Few learnings:

  • Thrift is quite slow and not that straightforward to use (after all, it was designed to provide entire communication layer for an application), but provides decent compression rate
  • Protobuf and Avro provide by far the most compact output (because of schema provided)
  • Protobuf library (protobufjs), unlike Avro, can't handle enumerations (Protobufjs requires raw integer values to be used whereas Avro supports semantic, string values)
  • Cap'n'Proto seems outdated and its JS plugin did not get any support for few years now, have to check the TS version
  • FlatBuffers is quite low-level and tricky to use (much more effort than those other tools)

My take on these results is that:

  • Protobuf, when using a compiled serialzier/deserializer for specific message(-s):
    • has a comfortable API
    • fast serialization / deserialization in browser
    • decent compression rate
    • relatively small bundle size increase
  • Flatbuffers:
    • great compression rate
    • tiny bundle size impact
    • great performance in browser
    • super-cumbersome API (well, that's low-level trade-offs for ya)

The source code for the tests could be found on my GitHub repo .

Under the cut you will find a stream of consciousness - my notes whilst implementing the tests for these tech.

Artem Shubovych

I have seen quite a few web applications which are passing heaps of data between client and server. Pretty much all of them use JSON for that purpose. And whilst that solves the business problem, some of those applications aim to provide nearly real-time user experience, and that's where the issues arise.

With the rise of web sockets, RTC and HTTP2 tech, the data transfer speed issues might be not so noticeable, but the more data app tries to transfer, the more pressing the matter gets. This issue also becomes more apparent on the server side - server has to process a lot more data in a request thread.

At The Trade Desk I have observed an approach, where we are transferring a list of strings (later we converted them to integers to widen the bandwidth) between high-loaded services (think 15 million requests per second with a hard time bound on request processing of 100 milliseconds).

I thought this is a cool concept, worth exploring deeper. For this matter, I have searched the Internet for similar approaches.

One of the readings was an article on the russian resource about speeding up a web application by switching from HTTP1 to HTTP2, utilizing various data compression formats: for static assets - WEBP, AVIF and progressive JPEG; for general data - various stream compression algorithms - GZIP, Brotli and ZSTD; alongside with different data serialization formats - MessagePack.

I decided to expand my search in the direction of serialization formats. In this article I compare few of those and focus on their performance in serializing different kinds of data (lists, nested objects, integers and strings, large and small datasets) and the serialization & deserialization performance in browser and the compression rates.

The formats covered are:

One of the optimizations we have achieved at The Trade Desk was 7 times reduction in data size by switching from string IDs to integer values. Think "something-else" we used to operate everywhere was assigned an integer ID of 4092 . Now that int is 4 bytes long, whereas the string value is 14 bytes long. That is more than 3x reduction in size, but you have to still store the mapping somewhere, which we already did (in our case).

But the overall idea is worth researching too - how much compression each format provides when working with long lists of strings and long lists of ints.

To make the thing more interesting, I came up with few various data types to be messed around:

  • a simple object Pet { name: string, kind: enum Kind { CAT, DOG } }
  • an object with an array of string identifiers StringIdsResource { ids: string[] }
  • an object with an array of integer identifiers StringIdsResource { ids: int[] }

As mentioned before, the metrics I'm going to be focusing on are:

  • encoding & decoding performance in browser environment
  • encoded message length (raw, as UTF-8 string and base-64 encoded UTF-8 string)
  • amount of runtime (bundled code) required to work with the format

To make it quick and easy, here's the summary (time measured in browser, on a nested object with a list of 1000 children of various data types) :

Serializer Encoding time Decoding time Encoded data size (byte array) Compression Encoded data size (base-64 utf-8 encoded) Bundle size
Avro 12ms 4ms 30003 77.16% 40004 111.7kb
BSON 10ms 11ms 98912 24.71% 131884 98.0kb
CBOR 3ms 4ms 89017 32.24% 118692 30.1kb
MessagePack 3ms 3ms 89017 32.24% 118692 27.7kb
Protobuf 13ms 3ms 38000 71.07% 50668 76.6kb
Protobuf, compiled 6ms 1ms 38000 71.07% 50668 30.0kb
Flatbuffers 9ms 3ms 32052 75.60% 42736 3.1kb
Thrift (binary) 42ms 6ms 45009 65.74% 60012 109.7kb
Thrift (compact) 33ms 11ms 36005 72.59% 48008 109.7kb

Few learnings:

  • Thrift is quite slow and not that straightforward to use (after all, it was designed to provide entire communication layer for an application), but provides decent compression rate
  • Protobuf and Avro provide by far the most compact output (because of schema provided)
  • Protobuf library (protobufjs), unlike Avro, can't handle enumerations (Protobufjs requires raw integer values to be used whereas Avro supports semantic, string values)
  • Cap'n'Proto seems outdated and its JS plugin did not get any support for few years now, have to check the TS version
  • FlatBuffers is quite low-level and tricky to use (much more effort than those other tools)

My take on these results is that:

  • Protobuf, when using a compiled serialzier/deserializer for specific message(-s):
    • has a comfortable API
    • fast serialization / deserialization in browser
    • decent compression rate
    • relatively small bundle size increase
  • Flatbuffers:
    • great compression rate
    • tiny bundle size impact
    • great performance in browser
    • super-cumbersome API (well, that's low-level trade-offs for ya)

The source code for the tests could be found on my GitHub repo .

Under the cut you will find a stream of consciousness - my notes whilst implementing the tests for these tech.

Preface

Some of the serialization tools listed in this blog require message (or rather data) schema to be defined beforehand. This might seem like unnecessary extra work, but if implemented correctly, it has quite a few benefits:

  • no need to ship an entire runtime / parser
  • type checking even in weakly typed languages
  • contract enforcing becomes an option, no real need for contract testing

Amongst technologies covered here, only three do not use data schema:

  • CBOR
  • BSON
  • MessagePack

But the others, which do use schemas, need the schema to be compiled before it is used.

Avro

First time I've heard about Avro is when I had to work with Kafka - it was used to enforce message format across queues.

With Avro, one does not really have to compile schema before it is used (although it is possible) - schema can be defined at runtime:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> avro </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'avsc/etc/browser/avsc-types'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AvroType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> avro</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Type</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forSchema</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'record'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'TimeframeResource'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  fields</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'dataPoints'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'array'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        items</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'record'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DataPoint'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          fields</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'timestamp'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'long'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'values'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'record'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'TimeframeValues'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                fields</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'category1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'double'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'category2'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'double'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'category3'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'double'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        default</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The only trick with Avro is that long is not really a type, for whatever reason. The 64-bit wide integers are very useful when working with DateTime to reduce the message size (consider 31-Oct-2022T09:34:00+10:00 (26 characters = 26 bytes) vs 1667172840 (64 bit = 2 bytes)). And the way to define this type in Avro is a bit quirky:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> LongType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> avro</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">types</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LongType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">__with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fromBuffer</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">readBigInt64LE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    toBuffer</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Buffer</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">alloc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        buf</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">writeBigInt64LE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">BigInt</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(n))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fromJSON</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    toJSON</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    isValid</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#179299;--shiki-dark:#81C8BE"> typeof</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'number'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    compare</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n1 </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n2 </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (n1 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n2 </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AvroType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> avro</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Type</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forSchema</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /* schema */</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    registry</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'long'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> LongType </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

But then, serialization and deserialization are extremely simple:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5.207119058209394</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">89.29685288758918</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">35.90829865270196</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">43.35796609790218</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">21.846789565420153</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">124.58032201029741</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AvroType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toBuffer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AvroType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromBuffer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(buf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

BSON

BSON is a schema-less library, so usage is as straightforward as it can be:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> BSON </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'bson'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5.207119058209394</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">89.29685288758918</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">35.90829865270196</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">43.35796609790218</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">21.846789565420153</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">124.58032201029741</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> BSON</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">serialize</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> BSON</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deserialize</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(buf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

CBOR

CBOR is very similar to BSON - it is a schema-less tool, so it is as straightforward as it gets:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CBOR </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'cbor-x'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5.207119058209394</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">89.29685288758918</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">35.90829865270196</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">43.35796609790218</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">21.846789565420153</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">124.58032201029741</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> CBOR</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">encode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> CBOR</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">decode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(buf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

MessagePack

MessagePack is the last one of the schema-less tools, so it is once again as straightforward as one might think:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MessagePack </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'msgpackr'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5.207119058209394</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">89.29685288758918</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">35.90829865270196</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">43.35796609790218</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">21.846789565420153</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">124.58032201029741</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MessagePack</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pack</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MessagePack</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unpack</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(buf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Protobuf

With Protobuf, the schema can be defined and parsed in runtime:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> protobuf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'protobufjs'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ProtobufProto </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `syntax = "proto3";</span></span>
<span class="line"></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">package testpackage;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">message TimeframeValues {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    double category1 = 1;</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    double category2 = 2;</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    double category3 = 3;</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">message Timeframe {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    int64 timestamp = 1;</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    TimeframeValues values = 2;</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">message TimeframeData {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    repeated Timeframe dataPoints = 1;</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">}</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ProtobufType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> protobuf</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(ProtobufProto)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">root</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lookupType</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'testpackage.TimeframeData'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

With parsing, one has to lookup the message type from the "root" type, before it can be used for serialization.

The schema can also be compiled as a separate build step:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">yarn</span><span style="color:#40A02B;--shiki-dark:#A6D189"> pbjs</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -t</span><span style="color:#40A02B;--shiki-dark:#A6D189"> static-module</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -w</span><span style="color:#40A02B;--shiki-dark:#A6D189"> commonjs</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ProtobufType.js</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ProtobufType.proto</span></span></code>

The serialization and deserialization then become quite straightforward:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5.207119058209394</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">89.29685288758918</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">35.90829865270196</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#40A02B;--shiki-dark:#A6D189">"timestamp"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Date</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022-05-05T21:11:22+10:00"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"values"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category1"</span><span style="color:#179299;--shiki-dark:#81C8BE">:-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">43.35796609790218</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category2"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">21.846789565420153</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189">"category3"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">124.58032201029741</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}},</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ProtobufType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">encode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">finish</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ProtobufType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">decode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(buf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

FlatBuffers

Defining schema with FlatBuffers looks like this:

<code>namespace testpackage;

table TimeframeValues {
  category1: float32;
  category2: float32;
  category3: float32;
}

table Timeframe {
  timestamp: int64;
  values: TimeframeValues;
}

table TimeframeData {
  dataPoints: [Timeframe];
}

root_type TimeframeData;
</code>

The schema is then compiled using the following command:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatc</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> flatbuffers-compiled-proto/</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --ts</span><span style="color:#40A02B;--shiki-dark:#A6D189"> TimeframeData.fbs</span></span></code>

One might think this is how to encode an object with FlatBuffers (which is a cumbersome low-level API already):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> builder </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flatbuffers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Builder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">startTimeframeData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">startDataPointsVector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> timestamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> category1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> category2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> category3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">startTimeframe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addTimestamp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(timestamp)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FlatbuffersTimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">startTimeframeValues</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FlatbuffersTimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addCategory1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> category1)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FlatbuffersTimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addCategory2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> category2)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FlatbuffersTimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addCategory3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> category3)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // alternatively: FlatbuffersTimeframeValues.TimeframeValues.createTimeframeValues(builder, category1, category2, category3);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endTimeframeValues</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addValues</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vs)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endTimeframe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addDataPoints</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> offset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endTimeframeData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">builder</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">finish</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(offset)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> builder</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">asUint8Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

But this won't do - an error would be thrown:

<code>Uncaught Error: FlatBuffers: object serialization must not be nested.
</code>

With FlatBuffers serialization is like managing the memory in C98 - you first allocate the memory, then you fill it with data, then you use it elsewhere:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> builder </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flatbuffers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Builder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tfs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> timestamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> category1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> category2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> category3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeValues</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createTimeframeValues</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> category1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> category2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> category3)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">startTimeframe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addTimestamp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timestamp)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addValues</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vs)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Timeframe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endTimeframe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dps </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createDataPointsVector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tfs)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">startTimeframeData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addDataPoints</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dps)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> offset </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endTimeframeData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(builder)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">builder</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">finish</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(offset)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> builder</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">asUint8Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Deserializing objects is also not all that similar with the other tech in this list - accessing each property is done via methods provided by the generated proto classes:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flatbuffers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ByteBuffer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timeframeData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FlatbuffersTimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRootAsTimeframeData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(buf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// accessing dataPoints: timeframeData.dataPoints(timeframeData.dataPointsLength() - 1).values().category1()</span></span></code>

This aspect makes FlatBuffers not so friendly to use. Meaning if you decide to incorporate it in your project, not only will you need to compile the schemas separately, but the effort to implement serialization might become a decisive factor against it, compared to other tools in this review.

Thrift

Schema for Thrift looks like this:

<code class="language-thrift">struct TimeframeValues {
  1: required double category1;
  2: required double category2;
  3: required double category3;
}

struct Timeframe {
  1: required i32 timestamp;
  2: required TimeframeValues values;
}

struct TimeframeData {
  1: required list&#x3C;Timeframe> dataPoints;
}
</code>

Compiling it uses tool thrift-typescript (for TypeScript & JS compilation):

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">yarn</span><span style="color:#40A02B;--shiki-dark:#A6D189"> thrift-typescript</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --outDir</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ./thrift-compiled-proto</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --rootDir</span><span style="color:#40A02B;--shiki-dark:#A6D189"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --sourceDir</span><span style="color:#40A02B;--shiki-dark:#A6D189"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> TimeframeData.thrift</span></span></code>

Thrift, similarly to FlatBuffers is a bit tricky to get running. First, it needs a protocol and a transport to operate. There are two protocols, TBinaryProtocol , which provides some level of compression and TCompactProtocol , which offers more compression. Then, similarly to FlatBuffers, the nested objects have to be serialized first. And finally, the API is not very user friendly - one might think using the constructors is sufficient, but in fact one has to rely on callbacks:

This won't do:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Buffer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thriftTransport </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thrift</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TBufferedTransport</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(buf)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binaryThriftProtocol </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thrift</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TCompactProtocol</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(thriftTransport)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ThriftType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TimeframeData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">obj</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">write</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(binaryThriftProtocol)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">binaryThriftProtocol</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flush</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Instead, one should use callback API and serialize nested objects first:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thriftBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thriftTransport </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thrift</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TBufferedTransport</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> res</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thriftBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> binaryThriftProtocol </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thrift</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TCompactProtocol</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(thriftTransport)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dataPoints </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">dp</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ThriftType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TimeframeValues</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(dp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">values)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ThriftType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Timeframe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timestamp</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timestamp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> values</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vs </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ThriftType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TimeframeData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dataPoints </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">obj</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">write</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(binaryThriftProtocol)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">binaryThriftProtocol</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flush</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thriftBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Deserialization is also messed up by these low-level APIs:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thrift</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TBufferedTransport</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">receiver</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">transport</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> protocol </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thrift</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">TCompactProtocol</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(transport)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  obj </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ThriftType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TimeframeData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">read</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(protocol)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">tr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Buffer</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> obj</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Serialization output

Let's consider serializing & deserializing a simple object of type Pet :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">enum</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PetKind</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  CAT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  DOG</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pet</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  kind</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PetKind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And the object for the experiments:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Rodrigo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kind</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DOG'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span></code>

First, let's take a look at schema-less serialization libraries - CBOR, BSON and MessagePack:

CBOR

<code>CBOR-encode: 0.779ms
CBOR-decode: 0.587ms
[CBOR]> pre-utf8 (25): &#x3C;Buffer b9 00 02 64 6e 61 6d 65 67 52 6f 64 72 69 67 6f 64 6b 69 6e 64 63 44 4f 47, dataView: DataView { byteLength: 25, byteOffset: 0, buffer: ArrayBuffer { [Uint8Contents]: &#x3C;b9 00 02 64 6e 61 6d 65 67 52 6f 64 72 69 67 6f 64 6b 69 6e 64 63 44 4f 47 00 06 00 05 00 04 00 0f 05 00 0f 10 04 00 04 00 25 c6 58 36 01 00 00 01 00 00 00 10 3e 58 0f 01 ff ff ff 31 00 00 00 c8 2e c6 58 36 01 00 00 09 00 00 00 00 ce 65 1c 01 3c c6 58 36 01 00 00 00 00 00 00 00 00 00 00 b0 80 cc 58 ... 8092 more bytes>, byteLength: 8192 } }>
[CBOR]> post-utf8 (23): 适dnamegRodrigodkindcDOG
[CBOR]> base-64 (36): uQACZG5hbWVnUm9kcmlnb2RraW5kY0RPRw==
[CBOR]> decoded: { name: 'Rodrigo', kind: 'DOG' }
</code>

BSON

<code>BSON-encode: 0.631ms
BSON-decode: 1.079ms
[BSON]> pre-utf8 (37): &#x3C;Buffer 25 00 00 00 02 6e 61 6d 65 00 08 00 00 00 52 6f 64 72 69 67 6f 00 02 6b 69 6e 64 00 04 00 00 00 44 4f 47 00 00>
[BSON]> post-utf8 (37): %☻namRodrigo☻kind♦DOG
[BSON]> base-64 (52): JQAAAAJuYW1lAAgAAABSb2RyaWdvAAJraW5kAAQAAABET0cAAA==
[BSON]> decoded: { name: 'Rodrigo', kind: 'DOG' }
</code>

MessagePack

<code>MessagePack-encode: 0.738ms
MessagePack-decode: 0.664ms
[MessagePack]> pre-utf8 (25): &#x3C;Buffer de 00 02 a4 6e 61 6d 65 a7 52 6f 64 72 69 67 6f a4 6b 69 6e 64 a3 44 4f 47, dataView: DataView { byteLength: 25, byteOffset: 0, buffer: ArrayBuffer { [Uint8Contents]: &#x3C;de 00 02 a4 6e 61 6d 65 a7 52 6f 64 72 69 67 6f a4 6b 69 6e 64 a3 44 4f 47 00 06 00 05 00 04 00 0f 05 00 0f 10 04 00 04 00 25 c6 58 36 01 00 00 01 00 00 00 10 3e 58 0f 01 ff ff ff 31 00 00 00 28 2e c6 58 36 01 00 00 08 00 00 00 00 ce 65 1c 01 fc c5 58 36 01 00 00 b0 2e c6 58 36 01 00 00 0c 00 00 00 ... 8092 more bytes>, byteLength: 8192 } }>
[MessagePack]> post-utf8 (16): ހ☻䮡me璯drigo䫩ndㄏG
[MessagePack]> base-64 (36): 3gACpG5hbWWnUm9kcmlnb6RraW5ko0RPRw==
[MessagePack]> decoded: { name: 'Rodrigo', kind: 'DOG' }
</code>

Except for MessagePack, which seem to utilize the tight byte-packing, the idea of these tools is to put field name before the field value and just pack the data bytes as tightly as possible.

Now, for the schema-enforced libraries:

Avro

<code>Avro-encode: 0.199ms
Avro-decode: 0.181ms
[Avro]> pre-utf8 (9): &#x3C;Buffer 02 0e 52 6f 64 72 69 67 6f>
[Avro]> post-utf8 (9): ☻♫Rodrigo
[Avro]> base-64 (12): Ag5Sb2RyaWdv
[Avro]> decoded: Pet { kind: 'DOG', name: 'Rodrigo' }
</code>

Protobuf

<code>Protobuf-encode: 2.723ms
Protobuf-decode: 0.231ms
[Protobuf]> pre-utf8 (11): &#x3C;Buffer 08 00 12 07 52 6f 64 72 69 67 6f>
[Protobuf]> post-utf8 (11):↕Rodrigo
[Protobuf]> base-64 (16): CAASB1JvZHJpZ28=
[Protobuf]> decoded: Pet { kind: 0, name: 'Rodrigo' }
</code>

Since there is no need to transfer field names and field types are already known, the big difference with the schema-enforced libraries is that there is only need to send the start & end markers of the object' data. Hence the big difference in message size.

Build time and bundle size

Since different tools require different stuff to run (like schema & message parsers, validators, etc.) and might require a separate build step to compile schemas, it might be valuable to know what you are dealing with.

Consider the data type used in the previous experiments:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TimeframeValues</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  category1</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> double</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  category2</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> double</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  category3</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> double</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Timeframe</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  timestamp</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> long</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  values</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TimeframeValues</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TimeframeData</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  dataPoints</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Timeframe[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Tech Bundle size
Avro 111.7kb
BSON 98.0kb
CBOR 30.1kb
MessagePack 27.7kb
Protobuf (parse schema) 76.6kb
Protobuf (compiled schema) 30.0kb
Flatbuffers 3.1kb
Thrift (compiled schema) 109.7kb

All of the above were build with TypeScript first and esbuild then with --minify option.

Conclusion

As for the best technology out of the ones reviewed here, I think Protobuf is the most viable one - the data compression (71% on mixed data), the bundle size (+30kb), the serialization (6ms) & deserialization (1ms) times result in the best overall ratio out there.

If your project needs to optimize on the transferred data amount without suffering from slowdowns (due to serialization & deserialization) or bigger client JS bundle, Protobuf is the way to go.

Do not even consider BSON, CBOR and MessagePack - at the same bundle size increase, they give very little data compression, so optimization would be pretty much pointless. They do serialize the data faster (6ms with Protobuf vs 3ms with CBOR or MessagePack), but they also deserialize the data slower (lowest is 3ms with MessagePack vs 1ms with Protobuf).

Jargon-free functional programming. Part 1: problem statement urn:uuid:1ac89718-4a26-5089-9e87-f4c69d1a1e79 2022-08-24T00:00:00Z 2022-08-24T00:00:00Z

Basics

Let me introduce you functional programming with as few jargonisms and buzz-words as possible.

Shall we start with a simple problem to solve: get a random board game from top-10 games on BoardGamesGeek website and print out its rank and title.

BoardGameGeek website has an API: a request GET https://boardgamegeek.com/xmlapi2/hot?type=boardgame will return an XML document like this:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">xml</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> version</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1.0"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> encoding</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"utf-8"</span><span style="color:#179299;--shiki-dark:#81C8BE">?></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">items</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> termsofuse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://boardgamegeek.com/xmlapi/termsofuse"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> id</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"361545"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rank</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">thumbnail</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://cf.geekdo-images.com/lD8s_SQPObXTPevz-aAElA__thumb/img/YZG-deJK2vFm4NMOaniqZwwlaAE=/fit-in/200x150/filters:strip_icc()/pic6892102.png"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">name</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Twilight Inscription"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">yearpublished</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> id</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"276182"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rank</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">thumbnail</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://cf.geekdo-images.com/4q_5Ox7oYtK3Ma73iRtfAg__thumb/img/TU4UOoot_zqqUwCEmE_wFnLRRCY=/fit-in/200x150/filters:strip_icc()/pic4650725.jpg"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">name</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Dead Reckoning"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">yearpublished</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">items</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

In JavaScript a solution to this problem might look something like this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">randomTop10Game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">randomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">randomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Quick and easy, quite easy to understand - seems good enough.

How about we write some tests for it? Oh, now it becomes a little bit clunky - we need to mock fetch call (Fetch API) and the Math.random . Oh, and the DOMParser with its querySelector and querySelectorAll calls too. Probably even console.log method as well. Okay, we will probably need to modify the original code to make testing easier (if even possible). How about we split the program into separate blocks of code?

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Okay, now we can test some of the bits of the program without too much of a hassle - we could test that every call of getRandomGame returns a different value (which might not be true) but within the given list of values. We could test the extractGames function on a mock XML document and verify it extracts all the &#x3C;item> nodes and its &#x3C;name> child. Testing fetchAPIResponse and getResponseXML and printGame functions, though, would be a bit tricky without either mocking the fetch , console.log and DOMParser or actually calling those functions.

Artem Shubovych

Basics

Let me introduce you functional programming with as few jargonisms and buzz-words as possible.

Shall we start with a simple problem to solve: get a random board game from top-10 games on BoardGamesGeek website and print out its rank and title.

BoardGameGeek website has an API: a request GET https://boardgamegeek.com/xmlapi2/hot?type=boardgame will return an XML document like this:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">xml</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> version</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1.0"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> encoding</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"utf-8"</span><span style="color:#179299;--shiki-dark:#81C8BE">?></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">items</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> termsofuse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://boardgamegeek.com/xmlapi/termsofuse"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> id</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"361545"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rank</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">thumbnail</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://cf.geekdo-images.com/lD8s_SQPObXTPevz-aAElA__thumb/img/YZG-deJK2vFm4NMOaniqZwwlaAE=/fit-in/200x150/filters:strip_icc()/pic6892102.png"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">name</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Twilight Inscription"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">yearpublished</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> id</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"276182"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rank</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">thumbnail</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"https://cf.geekdo-images.com/4q_5Ox7oYtK3Ma73iRtfAg__thumb/img/TU4UOoot_zqqUwCEmE_wFnLRRCY=/fit-in/200x150/filters:strip_icc()/pic4650725.jpg"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">name</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Dead Reckoning"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">yearpublished</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"2022"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">item</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">items</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

In JavaScript a solution to this problem might look something like this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">randomTop10Game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">randomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">randomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Quick and easy, quite easy to understand - seems good enough.

How about we write some tests for it? Oh, now it becomes a little bit clunky - we need to mock fetch call (Fetch API) and the Math.random . Oh, and the DOMParser with its querySelector and querySelectorAll calls too. Probably even console.log method as well. Okay, we will probably need to modify the original code to make testing easier (if even possible). How about we split the program into separate blocks of code?

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Okay, now we can test some of the bits of the program without too much of a hassle - we could test that every call of getRandomGame returns a different value (which might not be true) but within the given list of values. We could test the extractGames function on a mock XML document and verify it extracts all the &#x3C;item> nodes and its &#x3C;name> child. Testing fetchAPIResponse and getResponseXML and printGame functions, though, would be a bit tricky without either mocking the fetch , console.log and DOMParser or actually calling those functions.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  fetchAPIResponse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  getResponseXML</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  extractGames</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  getRandomTop10Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  printGame</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "./index"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"fetchAPIResponse"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bad response"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    beforeEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      global</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fetch </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jest</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"404 Not Found"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns rejected promise"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rejects</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toBe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"404 Not Found"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ok response"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    beforeEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      global</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fetch </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jest</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">        Promise</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">resolve</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `&#x3C;?xml version="1.0" encoding="utf-8"?>&#x3C;items>&#x3C;item rank="1">&#x3C;name value="Beyond the Sun"/>&#x3C;/item>&#x3C;/items>`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns rejected promise"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">resolves</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toBe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        `&#x3C;?xml version="1.0" encoding="utf-8"?>&#x3C;items>&#x3C;item rank="1">&#x3C;name value="Beyond the Sun"/>&#x3C;/item>&#x3C;/items>`</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"getResponseXML"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"null passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns no &#x3C;item> nodes"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"item"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toHaveLength</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"invalid text passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns no &#x3C;item> nodes"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"404 not found"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"item"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toHaveLength</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"blank document passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns no &#x3C;item> nodes"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'&#x3C;?xml version="1.0" encoding="utf-8"?>'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"item"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toHaveLength</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"valid document passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns &#x3C;item> nodes"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        '&#x3C;?xml version="1.0" encoding="utf-8"?>&#x3C;items>&#x3C;item rank="1">&#x3C;name value="Beyond the Sun"/>&#x3C;/item>&#x3C;/items>'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"item"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(items)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toHaveLength</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"extractGames"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"null document"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"throws an exception"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"empty document"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns empty array"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toStrictEqual</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"valid document"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns an array of games"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        `&#x3C;?xml version="1.0" encoding="utf-8"?>&#x3C;items>&#x3C;item rank="3">&#x3C;name value="Beyond the Sun"/>&#x3C;/item>&#x3C;/items>`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "text/xml"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toStrictEqual</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Beyond the Sun"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"getRandomTop10Game"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"null passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"throws an exception"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"empty array passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns undefined"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([]))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toStrictEqual</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"less than 10 element array passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns undefined"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomGames </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(randomGames)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toContain</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"10 or more element array passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"never returns undefined"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game7"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game8"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game9"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game10"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomGames </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(randomGames)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toContain</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"returns an instance of each game"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game7"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "7"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game8"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "8"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game9"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "9"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game10"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "10"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomGames </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(randomGames)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toStrictEqual</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(expect</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">arrayContaining</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"printGame"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"null passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"throws an exception"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"game passed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mockLogFn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> jest</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    beforeEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mockLogFn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"prints it to console"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "game 42"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "42"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(mockLogFn)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toHaveBeenCalledWith</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"#42: game 42"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

In a lot of ways, I personally find these tests quite... hacky. But they seem to cover most of the functionality.

Let us talk about corner cases. As in, what would happen if the API does not return the result? Or what would happen if the result is not a valid XML (like 404 Not Found text)? Or what would happen if the XML is valid, but it does not contain any items or item[rank]>name[value] nodes? Or what if it only returns 5 results (or any number of results less than 10 , for that matter)?

In most of the cases, the promise will get rejected (since an entire program is a chain of Promise.then calls). So you might think this is just fine and rely on the rejection logic handling (maybe even using Promise.catch ).

If you want to be smart about these error cases, you would need to introduce the checks to each and every step of the chain.

In "classic" JS or TS you might want to return null (or, less likely, use Java-style approach, throwing an exception) when the error occurs. This, however, comes with the need to introduce the null checks all over the place. Consider this refactoring:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doc) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">games) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

In case you don't want to bother with null values or want to have a better logging (not necessarily error handling), you can straight away throw an exception:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Received invalid XML'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">games) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No games found'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Less than 10 games received'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No game provided'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Failed'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Alternatively, since an entire program is a chain of promises, you could just return a rejected promise:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Received invalid XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">games) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'No games found'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Less than 10 games received'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'No game provided'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">error</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Failed'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

That's all good and nice and we seem to have covered most of the edge case scenarios (at least those we could think of). Now, what if I tell you the program is still not entirely correct? See those querySelector calls? They might return null if the node or the attribute is not present. And we do not want those empty objects in our program' output. This might be tricky to catch immediately while developing the code.

One might even argue that most of those errors would have been caught by the compiler, if we have used something like TypeScript. And they might be right - for the most part:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Received invalid XML'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">games) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No games found'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Less than 10 games received'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No game provided'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">error</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Failed'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Not too many changes, but those pesky little errors were caught at development time, pretty much. The testing is still a challenge, though.

There is a application design approach which might be able to solve quite a bit of the aforementioned issues. Let me introduce you to the world of functional programming without a ton of buzzwords and overwhelming terminology.

Proceed

Jargon-free functional programming. Part 2: functional wrappers urn:uuid:7585e8b4-d44b-5eee-97c7-abf6a1b0b6d1 2022-08-24T00:00:00Z 2022-08-24T00:00:00Z

Disclaimer

A big disclaimer before diving too deep: I am going to introduce all of the concepts without relying on any frameworks, libraries, specific programming languages and whatnot - just sticking to the hand-written TypeScript. This might seem like a lot of boilerplate and overhead for little benefit, but (with notes of a philosophy) the biggest benefit is in the cost of detecting and fixing errors in the code:

  • IDE highlighting an error (and maybe even suggesting a fix) - mere seconds of developer's time
  • Local build (compiling the code locally, before pushing the code to the repository) - minutes, maybe tens of minutes
  • CI server build, running all the tests possible - around an hour
  • Pre-production environment (manual testing on dedicated QA / staging environment or even testing on production) - around few hours, may involve other people
  • Production - measured in days or months and risking the reputation with the customers

Hence if we could detect the errors while writing the code the first time - we could potentially save ourselves a fortune measured in both time and money.

Fancy-less introduction to functional programming

The ideas of functional programming are quite simple. In functional programming the assumption is that every function only operates on the arguments it has been passed and nothing else. It can not change the "outer world" - it can have values temporarily assigned to internal constants, nothing more - take it as there are no variables. A function should always return the same result for the same arguments, so functions are always predictable, no matter how many times you call them.

That sounds good and nice, but how does that solve the issues of the above problem, you might ask. For the most part the functions we have extracted already comply with the ideas of functional programming - do they not?

Well, not really. For once, fetching the data from the API is a big questionmark on how it fits into the picture of functional programming. Leaving the fetching aside, we have a random call in the middle. We also log some output to the console (and thus change the "outer world", outside the printGame function).

For a lot of things like those, functional programming tries to separate the "pure functional operations" and "impure operations".

See, in functional programming you operate these "pure functions", which only use constants and inputs to produce their outputs. So a program would be nothing but a chain of function calls. With "simple" functions, returning the values which the next function in the chain can take as an input argument, this is quite easy.

Take the code above as an example:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This could have been written as

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Since each next function in the chain accepts exactly the type the previous function has returned, they all combine quite well.

JFYI : in other languages and some libraries there are operators to combine functions into one big function:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([ getResponseXML</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extractGames</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getRandomTop10Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printGame ])(response)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

or

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">response </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        getResponseXML</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">extractGames</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getRandomTop10Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">printGame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">aplly</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span></code>

You will understand why this matters in a minute.

There are also functions which need to interact with the outer world. In that case, functional programming suggests that we wrap them in specific constructions and do not run them immediately. Instead, we weave them into the program, describing what would happen to the result of the wrapped function call when we get one. This makes programs again, "pure functional", "safe" (as in not operating outside of the boundaries of the program itself, all is contained in the function call chains). Then, once we run the program, we enter the world of "unsafe" and execute all those wrapped functions and run the rest of the code once we get the results in place.

Sounds a bit hard to comprehend.

Let me rephrase this with few bits of code.

For the problem above, we are trying to get the response of an API somewhere in the outer world. This is said to be an "unsafe" operation, since the data lives outside of the program, so we need to wrap this operation in a "safe" manner. Essentially, we will create an object which describes an intention to run the fetch call and then write our program around this object to describe how this data will be processed down the line, when we actually run the program (and the fetch request together with it).

Let's go through the thought process all together: we first need a class to wrap an unsafe function without executing it :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> intentionFunc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

We then need a way to explicitly execute this function when we are ready to do so:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> intentionFunc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The last piece is we want to be able to chain this function with some other function in a safe manner (e.g. again, wrap the chained function):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> intentionFunc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Essentially, we save the function we intend to run in the intentionFunc member of an IO class. When we want to describe what would happen to the result of the data, we return a new IO object with a new function - a combination of a function we will call around the call to the function we saved. This is important to understand why we return a new object: so that we do not mutate the original object.

You might see this new IO thing is very similar to the Promise available in JS runtime already. The similarities are obvious: we also have this chaining with the then method. The call to the then method also returns a new object.

But the main issue with Promise is that they start running the code you passed in the constructor immediately. And that is exactly the issue we are trying to resolve.

Now, let us see how we would use this new IO class in the original problem:

<code><span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span></code>

That would not work, however, since fetch call will return a Promise . So we need to somehow work with Promise instances instead. Let me postpone this discussion for a short while.

Spoiler: we could have tried implementing an unpromisify helper which would make the fetch call synchronous, something like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> unpromisify</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">promiseFn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isReady</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    promiseFn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isReady </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">error </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isReady </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isReady)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">error) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

But in JS world, promises start executing not immediately, but once you leave the context of a currently running function. So having that endless while loop, waiting for a promise to get resolved has zero effect since this loop will be running until the end of days, but unless you exit the function beforehand, the promise won't start executing because JS is single threaded and the execution queue / event loop prevents you from running the promise immediately.

End of spoiler

Artem Shubovych

Disclaimer

A big disclaimer before diving too deep: I am going to introduce all of the concepts without relying on any frameworks, libraries, specific programming languages and whatnot - just sticking to the hand-written TypeScript. This might seem like a lot of boilerplate and overhead for little benefit, but (with notes of a philosophy) the biggest benefit is in the cost of detecting and fixing errors in the code:

  • IDE highlighting an error (and maybe even suggesting a fix) - mere seconds of developer's time
  • Local build (compiling the code locally, before pushing the code to the repository) - minutes, maybe tens of minutes
  • CI server build, running all the tests possible - around an hour
  • Pre-production environment (manual testing on dedicated QA / staging environment or even testing on production) - around few hours, may involve other people
  • Production - measured in days or months and risking the reputation with the customers

Hence if we could detect the errors while writing the code the first time - we could potentially save ourselves a fortune measured in both time and money.

Fancy-less introduction to functional programming

The ideas of functional programming are quite simple. In functional programming the assumption is that every function only operates on the arguments it has been passed and nothing else. It can not change the "outer world" - it can have values temporarily assigned to internal constants, nothing more - take it as there are no variables. A function should always return the same result for the same arguments, so functions are always predictable, no matter how many times you call them.

That sounds good and nice, but how does that solve the issues of the above problem, you might ask. For the most part the functions we have extracted already comply with the ideas of functional programming - do they not?

Well, not really. For once, fetching the data from the API is a big questionmark on how it fits into the picture of functional programming. Leaving the fetching aside, we have a random call in the middle. We also log some output to the console (and thus change the "outer world", outside the printGame function).

For a lot of things like those, functional programming tries to separate the "pure functional operations" and "impure operations".

See, in functional programming you operate these "pure functions", which only use constants and inputs to produce their outputs. So a program would be nothing but a chain of function calls. With "simple" functions, returning the values which the next function in the chain can take as an input argument, this is quite easy.

Take the code above as an example:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This could have been written as

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Since each next function in the chain accepts exactly the type the previous function has returned, they all combine quite well.

JFYI : in other languages and some libraries there are operators to combine functions into one big function:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([ getResponseXML</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> extractGames</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getRandomTop10Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printGame ])(response)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

or

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">response </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        getResponseXML</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">extractGames</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getRandomTop10Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">printGame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">aplly</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span></code>

You will understand why this matters in a minute.

There are also functions which need to interact with the outer world. In that case, functional programming suggests that we wrap them in specific constructions and do not run them immediately. Instead, we weave them into the program, describing what would happen to the result of the wrapped function call when we get one. This makes programs again, "pure functional", "safe" (as in not operating outside of the boundaries of the program itself, all is contained in the function call chains). Then, once we run the program, we enter the world of "unsafe" and execute all those wrapped functions and run the rest of the code once we get the results in place.

Sounds a bit hard to comprehend.

Let me rephrase this with few bits of code.

For the problem above, we are trying to get the response of an API somewhere in the outer world. This is said to be an "unsafe" operation, since the data lives outside of the program, so we need to wrap this operation in a "safe" manner. Essentially, we will create an object which describes an intention to run the fetch call and then write our program around this object to describe how this data will be processed down the line, when we actually run the program (and the fetch request together with it).

Let's go through the thought process all together: we first need a class to wrap an unsafe function without executing it :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> intentionFunc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

We then need a way to explicitly execute this function when we are ready to do so:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> intentionFunc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The last piece is we want to be able to chain this function with some other function in a safe manner (e.g. again, wrap the chained function):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> intentionFunc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Essentially, we save the function we intend to run in the intentionFunc member of an IO class. When we want to describe what would happen to the result of the data, we return a new IO object with a new function - a combination of a function we will call around the call to the function we saved. This is important to understand why we return a new object: so that we do not mutate the original object.

You might see this new IO thing is very similar to the Promise available in JS runtime already. The similarities are obvious: we also have this chaining with the then method. The call to the then method also returns a new object.

But the main issue with Promise is that they start running the code you passed in the constructor immediately. And that is exactly the issue we are trying to resolve.

Now, let us see how we would use this new IO class in the original problem:

<code><span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span></code>

That would not work, however, since fetch call will return a Promise . So we need to somehow work with Promise instances instead. Let me postpone this discussion for a short while.

Spoiler: we could have tried implementing an unpromisify helper which would make the fetch call synchronous, something like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> unpromisify</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">promiseFn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> isReady</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    promiseFn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isReady </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">error </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isReady </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">isReady)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">error) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

But in JS world, promises start executing not immediately, but once you leave the context of a currently running function. So having that endless while loop, waiting for a promise to get resolved has zero effect since this loop will be running until the end of days, but unless you exit the function beforehand, the promise won't start executing because JS is single threaded and the execution queue / event loop prevents you from running the promise immediately.

End of spoiler

For now, let us pretend this code would magically work, so we can talk about one important matter. As I mentioned above, simple functions combine easily if one function accepts the same argument type the previous function returns. Think extractGames and getRandomTop10Game - getRandomTop10Game accepts an argument of type Array&#x3C;Game> while extractGames returns just that - Array&#x3C;Game> . But with this new construct of ours, IO , combining anything would be tricky:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// since Function is not a typed interface in TypeScript</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// I have extracted a simple 1-argument function type</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func </span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> intentionFunc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">arg</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(arg)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">arg</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">intentionFunc</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(arg)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Received invalid XML'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">games) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No games found'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Less than 10 games received'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No game provided'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // needed as `fetchAPIResponse`, the initial `IO` object in the chain, does not take any arguments</span></span></code>

Except for a tricky class declaration to support strong types by TypeScript, not much is different, huh?

The one big issue with almost any of the functions we have is that they not always produce results. And that is an issue, since functional programming dictates a function must always produce one.

The way we deal with this situation in functional programming is by using few helper classes, which describe the presence or abscence of a result. You might actually know them by heart: T? also known as T | null , T1 | T2 - TypeScript has it all:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> undefiend</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#179299;--shiki-dark:#81C8BE"> ??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#179299;--shiki-dark:#81C8BE"> ??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Whereas with the former, optional values, you can do chaining to some extent, this becomes a burden with alternate types:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGame3</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (name </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid response'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML3</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Received invalid XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames3</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (doc </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">instanceof</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [] </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (name </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalida data in XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game3</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">instanceof</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame3</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (game </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">instanceof</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Observe how all those instanceof checks and questionmarks and pipes infested the code.

Let us have more conscise wrappers, very similar to what other functional programming technologies have:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> option</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> null</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value) </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">none</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> none</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The simplest (yet not entirely helpful) way to handle exceptions in functional programming world would be using a wrapper like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This might not look as simplistic or clean when defined, but see how it changes the code:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">gs</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gs[Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">g</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">g</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Now, there are two parts where we still have those ugly questionmarks:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Let's see if we can utilize the new helper classes to beautify this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Now the issue is: the createGame function takes an Element and returns a Maybe&#x3C;Game> , but the extractGames function should return an Either&#x3C;Error, Array&#x3C;Game>> . So we can't just write something like this and expect it to work:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

There simply is no constructor to convert from Maybe&#x3C;T> to Either&#x3C;A, B> both technically, in the code, and logically - what would be the Left and what would be the Right then? One might argue, for None we could return Left&#x3C;?> and for Some&#x3C;A> we could return Right&#x3C;A> . That would be the closest to truth, but we still need to come up with a type for Left .

This might actually be a good time to consider if these two types have something in common and, potentially, extract few interfaces.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toEither</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> option</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> null</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value) </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">none</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> none</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Some</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toEither</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> None</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toEither</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> leftToMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> rightToMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    static</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Left</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    leftToMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    rightToMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">none</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    override</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> C</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    leftToMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">none</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    rightToMaybe</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // TODO: flatten</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toEither</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'bad item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">accEither</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            accEither</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                createGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toEither</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'bad item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> game])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Either</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Received invalid XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

But we can do better than this: we can get rid of all those Either and Maybe in functions which do not throw an error:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatMap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Received invalid XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">accEither</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        accEither</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatMap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            createGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toEither</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'bad item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> game])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Either</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Not enough games'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games[Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Now if we try to compose the program, we would get quite a few "type mismatch" errors:

<code><span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

yielding

<code>Argument of type 'Either&#x3C;Error, XMLDocument>' is not assignable to parameter of type 'XMLDocument'.
    Type 'Either&#x3C;Error, XMLDocument>' is missing the following properties from type 'XMLDocument': addEventListener, removeEventListener, URL, alinkColor, and 247 more.

Argument of type 'Either&#x3C;Error, Game[]>' is not assignable to parameter of type 'Game[]'.
    Type 'Either&#x3C;Error, Game[]>' is missing the following properties from type 'Game[]': length, pop, push, concat, and 25 more.

Argument of type 'Either&#x3C;Error, Game>' is not assignable to parameter of type 'Game'.
    Type 'Either&#x3C;Error, Game>' is missing the following properties from type 'Game': name, rank
</code>

Let us follow the types being passed around:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// () ~> PromiseIO&#x3C;string></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// r: string -> getResponseXML(XMLDocument): Either&#x3C;Error, XMLDocument> ~> PromiseIO&#x3C;Either&#x3C;Error, XMLDocument>></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// doc: Either&#x3C;Error, XMLDocument> -> extractGames(Array&#x3C;Game>): Either&#x3C;Error, Array&#x3C;Game>> ~> PromiseIO&#x3C;Either&#x3C;Error, Array&#x3C;Game>>></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// games: Either&#x3C;Error, Array&#x3C;Game>> -> getRandomTop10Game(Array&#x3C;Game>): Either&#x3C;Error, Game> ~> PromiseIO&#x3C;Either&#x3C;Error, Game>></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// game: Either&#x3C;Error, Game> -> printGame(Game): void ~> PromiseIO&#x3C;void></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // () ~> void</span></span></code>

The issues begin when we try to call map on PromiseIO&#x3C;Either&#x3C;Error, XMLDocument>> :

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// => PromiseIO&#x3C;Either&#x3C;Error, XMLDocument>></span></span></code>

Let's recall how the method map on PromiseIO&#x3C;A> looks like:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    map</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

So it expects a function which takes the type which PromiseIO wraps and returns a new type to be wrapped in PromiseIO . But the type current PromiseIO wraps is Either&#x3C;Error, XMLDocument> . While the function we pass, extractGames looks like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span></code>

See the issue?

We could have fixed it by adding few more nested functions, like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">docE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> docE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatMap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc)))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">gamesE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gamesE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatMap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games)))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">gameE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gameE</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game)))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Or by changing the signature of the functions to take Either&#x3C;Error, ?> instead.

But there is a more neat way to handle cases like this in functional programming.

Since the entire program is a chain of andThen and andThenWrap calls on different Wrappable objects, we can create one which will wrap the try..catch expression.

Consider the code which might fail:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This might not return what we need, according to the DOMParser documentation . When the string passed to the parseFromString method is not a valid document, the object returned would be a document with a single node - &#x3C;parsererror> . Normally, in JS or TS, we would either return an "invalid" value (think null or undefined ) or throw an exception.

In functional programming we could get away with returning a Maybe or Either object.

However, let us consider throwing exception just to paint the bigger picture:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#error_handling</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'parsererror'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            throw</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Parser error'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (e) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

The above function, once called, will actually do some work . Luckily, in this specific case it won't do anything too "offensive" in terms of functional programming restrictions (like going to the database or making network calls). But it will do something rather than just return a value .

Every time we call this function, the new DOMParser will be created and it will parse the string.

In functional programming world, as mentioned above, the program is just a chain of calls. So the way to handle situations like this would be to somehow wrap the actual work and only execute it upon request.

The best way we could wrap work is in a function which is yet to be called:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

We then should allow for this code to be worked around in a "callback" manner (as you might be familiar with the concept from NodeJS and event handlers in browser JS) - the entire program should build upon a concept of "when the result of this execution becomes available".

The way to do so is already described above in terms of Wrappable class with its andThen and andThenWrap methods:

<code><span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> XWrappable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">document</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> doSomething</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document))</span></span></code>

Hence we could build a new Wrappable which would wrap both the logic in the try block and the logic in the catch block. However, it should not call neither of those blocks of logic until explicitly requested - so we should add a new method to this new wrappable - to call the logic and return a certain value.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> task</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> exceptionHandler</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unknown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    runExceptionW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (e) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exceptionHandler</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now the program from the beginning of the article can be re-written as follows:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> doc </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'parsererror'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Parser error'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Just to confirm once more if you are still asking "why bother with this ExceptionW thing? why not to use Either right away?": this whole ExceptionW thing allows us to postpone running the actual logic and build the entire program as a function of the result of this logic. In turn, when we are ready to execute the entire program, we can run this wrapped logic.

Let us see how this new function can be used in the program:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">result</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'success'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

There is a little bit of a quirk around type casting ( (???.runExceptionW() as Either&#x3C;Error, XMLDocument>).andThen ). We can solve it by slightly modifying the runExceptionW method:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">runExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">W </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> W</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> W</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (e) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exceptionHandler</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> W</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

With that, the code becomes a little bit cleaner:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">result</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'success'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

With this new concept of wrapping an entire blocks of functionality in a Wrappable , we can solve a similar problem with the initial program: promises.

Instead of just creating a promise object together with the Wrappable , we can instead hide it in a function.

Let us do this step by step. First, the interface implementation and the overall skeleton of a new class:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now, to wrap the promise:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> task</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And running the wrapped promise:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> task</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Note how I explicitly called it "unsafe" - since promise can (and, most likely, will) work with an outside world, we should only run it when we are ready to run the whole program, so it immediately produces the result as a function of whatever the wrapped promise has returned.

Then, when we need to chain the logic off that promise, we do not really need to call the promise - instead, we create a new Wrappable instance which will call the promise somewhere in the future.

So instead of calling wrappedPromise.then(func) , which is now wrapped in a function () => Promise&#x3C;A> , we create a new PromiseIO wrappable with a new function, which will do something when the promise returns .

This is better explained with the code, in my opinion:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> task</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Unfortunately, this won't work. The issue is in the andThenWrap method. Recall the interface of Wrappable&#x3C;A> :

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func: Func</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">): Wrappable</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func: Func</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Wrappable</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">): Wrappable</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Now the code we have in there right now will work if the function func returned B , which would be exactly what andThen method does:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// func: Func&#x3C;A, B></span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// => Promise&#x3C;A>.then((a: A) => func(a)) => Promise&#x3C;B></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// seems OK, gives PromiseIO&#x3C;B></span></span></code>

But since the function func returns PromiseIO&#x3C;B> instead, the result would be slightly different:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// func: Func&#x3C;A, PromiseIO&#x3C;B>></span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// => Promise&#x3C;A>.then((a: A) => func(a)) => Promise&#x3C;PromiseIO&#x3C;B>></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// this gives PromiseIO&#x3C;PromiseIO&#x3C;B>>, can't return from `andThenWrap`</span></span></code>

But notice how this is a nested PromiseIO object - can we maybe "unwrap" and "repack" it?

Turns out, we can - remember how a Promise&#x3C;A>.then(() => Promise&#x3C;B>) resolves in Promise&#x3C;B> . We can utilize this property of Promise , if the function we wrap will return Promise&#x3C;Promise&#x3C;B>> .

And that's where our unsafeRun method can be utilized within the function we wrap:

<code><span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// gives Promise&#x3C;A></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// this gives the Promise&#x3C;PromiseIO&#x3C;B>></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p2</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p3</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">p</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// this gives Promise&#x3C;B></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // at this stage we have Promise&#x3C;Promise&#x3C;B>>, which is automatically converted to Promise&#x3C;B></span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // passing it to the constructor of PromiseIO, wrapped in a function, will give PromiseIO&#x3C;B></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

and then

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> task</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">            new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">                this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            )</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">p</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now let us build our solution again, using this newly acquired wrappable:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Uh-oh, there is an issue with the types again:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// PromiseIO&#x3C;string></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// PromiseIO&#x3C;ExceptionW&#x3C;XMLDocument>></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// doc is now ExceptionW&#x3C;XMLDocument></span></span></code>

So we can not really use the existing functions directly - the types mismatch. The issue is that they are nested twice already - PromiseIO&#x3C;ExceptionW&#x3C;XMLDocument>> . And the extractGames function expects just the XMLDocument as an input. Is there a way to extract the double-wrapped value?

Well, in functional programming, we use another wrappable (oh really) which ignores the outside wrappable and operates on the nested one. We call them "transformers":

<code><span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// PromiseIOT&#x3C;string>, the transformer</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// unpacks the string, runs the function, and packs everything back in PromiseIOT</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc)) </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// unpacks the XMLDocument, runs the function, and packs everything back in PromiseIOT</span></span></code>

So this new thing is only helpful for dealing with whatever PromiseIO wraps. And, unfortunately, there needs to be a new one for whatever the new wrappable you come up with. This is understandable to some extent, since each "external" wrappable would handle the functions andThen and andThenWrap differently, so there can not really be a universal one.

Let's see how we can create one for PromiseIO , step-by-step.

First things first, the skeleton of a transformer:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And the thing we wrap, which is a PromiseIO&#x3C;A> :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And, as in case with PromiseIO itself, there has to be a way to run the promise (since it is wrapped). We will simply expose the value we wrap - as unsafe as it might look, the value we wrap is a wrapped promise already:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ???</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    runPromiseIOT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Note how it has to be PromiseIO&#x3C;Wrappable&#x3C;A>> - so the value PromiseIO wraps is a Wrappable on its own. This is where the transformers differ from the "simple" wrappers - if PromiseIO (the thing transformer wraps) would wrap a simple type ( PromiseIO&#x3C;A> ) - then there is no need for a transformer - just use the wrapper' interface directly.

Now, to the implementation: the function passed to andThen and andThenWrap methods would be applied to the thing the PromiseIO wraps. And the transformer wraps that PromiseIO object. Hence we need to call this.value.andThen() to get to the value PromiseIO wraps. But since that value is a wrapped type itself, we call andThen on it too:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func: Func</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">): PromiseIOT</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">PromiseIOT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">this.value.andThen(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">m</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And when we want to return a new wrappable to be wrapped in a PromiseIO , we simply use andThenWrap on a nested-nested value:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func: Func</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Wrappable</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">): PromiseIOT</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    return new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">PromiseIOT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">this.value.andThen(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">m</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The whole transformer looks like this now:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">m</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThenWrap</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">func</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">m</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(func)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    runPromiseIOT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Wrappable</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

To incorporate it in the program:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span></code>

This won't do, since fetchAPIResponse returns PromiseIO&#x3C;string> , meaning it wraps the simple type. And we need a Wrappable instead - otherwise we don't need the transformer. Conveniently for us, the next function in the chain takes that string value and returns a wrappable, ExceptionW&#x3C;XMLDocument> . So we can smash them together and pass to the PromiseIOT :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Now, there is one thing to recall from the previous wrappable we made, ExceptionW - the logic it wraps will only be executed upon request. And we need to incorporate this request in the program.

Since our program so far looks the way it looks, it's type is PromiseIOT , which does not have a way to run ExceptionW it wraps. In fact, it does not even have an interface to do so, since we have explicitly designed it to run all the operations on the doubly-nested type. We do have one option, though - to run the ExceptionW right after we have fetched the response:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">ew</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ew</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Note how we are not immediately running the logic wrapped by ExceptionW , but deferring it to the point in the future when the Promise returns with the response (or failure). So the chain of function calls is still within the restrictions of functional programming (or rather pure functions) mentioned in the beginning of this article.

Now the only thing left is to put the rest of the calls matching the types to the andThen or andThenWrap methods and run the entire program:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">ew</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ew</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runPromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Leaving all the "boilerplate" code aside (all those wrappables), this is how our program looks like so far:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ExceptionW</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> XMLDocument</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Received invalid XML'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Element</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Maybe</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        name</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">n</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">accEither</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> item</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        accEither</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            createGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(item)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">convert</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'bad item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">                    game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> game])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                )</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Either</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Not enough games'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games[(Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'RESULT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">w</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runExceptionW</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThenWrap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">runPromiseIOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">program</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Compare it to the initial implementation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchAPIResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`https://boardgamegeek.com/xmlapi2/hot?type=boardgame`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> DOMParser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFromString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(response</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/xml"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Received invalid XML'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> XMLDocument</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelectorAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'items item'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> items</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">item</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rank'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> item</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'name'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAttribute</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'value'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">games) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No games found'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Less than 10 games received'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> randomRank </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">floor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games[randomRank]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'No game provided'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> log </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(log)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fetchAPIResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getResponseXML</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">doc</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> extractGames</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(doc))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> printGame</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(game))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">error</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Failed'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> error))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

A poor conclusion

Note: this is a work-in-progress part of the article, hence this conclusion is rather poor - it lacks more examples and more substantial comparison. Bear with this while I am working on the proper one.

To me they both look quite similar. So was there any value in all this rewrite? Let's find it out together!

How about testing?

There is a big test suite for the initial implementation at the top of this article.

How do we go about testing this true-to-functional-programming version though?

We can apply it to this new code with few minor changes around assertions - now instead of expecting an exception to be thrown or a value immediately returned, we need to check if the value returned by the function is Left or Right and check the wrapped value.

How about testing the program as a whole? Well now, since the program is just a value, we can easily test its value. Dang, by replacing the functions in the chain we can even test different behaviours of the program! As in, instead of using fetchAPIResponse we can pass in a different instance of PromiseIO wrapping a completely wild value and see how the program would process it.

Errors are not a problem now - they are values, not breaking the execution of a program.

Interacting with the outer world is a breeze - just substitute the fetch with any Promise you want and it still won't break the whole program.

Now, here's the catch: I am not trying to sell you functional programming as the Holy Grail of developing the software and a silver bullet to every problem you might have.

In fact, there is a bug in the current true-to-functional-programming implementation, which is way easier to pin-point with the "conventional" error logs in the console. However, to find it, one first must run the program. With the functional-programming-implementation, the program will simply result in a Either&#x3C;Error, unknown>.Left value, without providing exact reason for the error.

The bug is tiny but pesky:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Not enough games'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">right</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(games[(Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Issue is in the games[(Math.random() * 100) % 10] expression: (Math.random() * 100) % 10 is a floating-point number. So most often, this will produce an undefined value.

And thus we come to the bigger issue, not related to the functional programming itself, but rather the issue with TypeScript: in order for one to notice this issue, the code must be run. But it would have not even been an issue if there was a mechanism in place to prevent accessing the array elements by randomly typed index.

We can mitigate it in a similar manner we have dealt with all the problems in this whole process of rewriting the program in a true functional programming way: implement a new class which would wrap an array of elements of a same type and provide a reasonable interface to access the elements.

Roughly put, if there was a class List&#x3C;A> which would return a Maybe&#x3C;A> when trying to access an element of the list by index, the program would have looked differently:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getRandomTop10Game</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">games</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Either</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Either</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Game</span><span style="color:#179299;--shiki-dark:#81C8BE">>.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">left</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Not enough games'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> game</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Game</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> games</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">at</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toEither</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Bad game index in the list of games'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

And the whole program would have resulted in a Left&#x3C;Error> with a message rather than some misleading exception (with a stack trace, though).

Resources

There are some resources I used when coming up with this article in different programming languages and full of jargon specific to functional programming, but here they are anyways:

Jargon-free functional programming. TL;DR urn:uuid:2e1fc49e-8f19-52b2-8a4a-9f67ee98962f 2022-08-11T00:00:00Z 2022-08-11T00:00:00Z Jargon-free functional programming. TL;DR Artem Shubovych

This is a boiled-down version of a much longer read, Jargon-free functional programming , giving a brief and visual introduction to the concepts of a real-world functional programming. This blog is aimed at people who already know something about programming and want to learn what the heck functional programming is, how is it different to "normal" programming and how does it look like in a real world.

In a non-functional world, the code we write depends on anything - a function, aside from its arguments, is free to use environment variables, global variables, outer scope, dependency injection - pretty much anything.

Moreover, it can modify all of the above (including outer scope, global and environment variables, etc.).

In a functional programming world we restrict a function to only rely on its arguments (or nothing at all).

But what about things like databases, user input, network communication, exceptions?

A typical application involving all of the above could be explained algorithmically as the endless loop, waiting for some input to appear before doing something (waiting for database query to complete, waiting for user to provide input, waiting for a network request to complete).

And every step of the program is described as a sequence of actions (potentially involving some rather trivial decision making). This approach is known as "imperative programming" and is very commonly used.

In reality, however, every step of this algorithm can go wrong in many different ways - each step is free to modify some global state (think OS and filesystem), it can fail terribly with an exception. Moreover, anything from the outside world (think OS or dependency injection) can break into the program and change any value or state of the program.

In a functional programming world, functions (and programs) are not described as sequences of commands - instead, they are more like recipes for calculations that will happen once all the requirements are provided.

The way to handle all the nifty things such as exceptions, networking, databases, etc. is to wrap a function which works with a result of the "unsafe" operation in a safe container. This container won't execute the function - just hold it for a while. However, this container would have two special properties: an ability to run the underlying function when it is deemed safe and an ability to be connected to other containers of the same type .

Each container will perform its very specific role - handling exceptions to return a value instead of breaking, running some input-output operations (incl. networking and databases), etc. We assume containers already do these operations in a safe manner - meaning they do not change anything in the program outside of themselves (think global variables, outer scope, etc.) and they always return a value. They only execute the function they wrap once requested explicitly.

By making it so that safe containers of different types can not be chained, we eliminate the chance of unexpected program failure. And we make sure at any point in time we can say what a program is doing exactly by just looking at its types.

By connecting such containers in a chain, we make programs.

But these chains do not do anything until they are explicitly executed.

A program is a chain of functions, wrapped in "safe" constructs, which is executed "at the end / edge of the world" - meaning program is thought to be executed only once. If all the blocks of this chain of containers succeed - the entire program succeeds.

If any of the blocks fails - the program does not exit or terminates, the failed block simply returns a different value.

All the logic is hidden in those "safe" constructs - it is isolated from the rest of the world.

Those containers are only allowed access to their direct arguments. It is guaranteed to never break and always return a value (which might be wrapped in another "safe" construct).

A program made of these safe recipes on how to calculate the result is just another recipe itself - essentially a series of recipes.

This safe set of recipes is then thrown together with a bunch of inputs into a grinder called "real world", where nothing is safe and everything can happen (theoretically).

In the grinder, the dish is being cooked from the inputs, following the recipes thrown to the grinder. The result of this cooking might be another program itself, which can then be recycled by being thrown back into the grinder - that would happen if a program enters the (infinite) loop, waiting for some inputs - it is essentially becomes a new program, which also needs to be executed when all the requirements are met.

In order to build one of those containers, one starts by creating a simple class.

The class must hold a function without running it.

There should be a way to link (chain) this container with some other function, creating a new safe container.

And finally there should be a way to execute the function wrapped by this safe container.

The details of each container' implementation is what makes them different. For few examples, the container which makes an arbitrary function safe (in this case we assume it does some input-output stuff) could look like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> f</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> g</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

A container which wraps a function returning a Promise might look similar (except all the dancing around Promise API):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> f</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

You can see the pattern - these classes all have very similar interface. Hence you can extract it:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Container</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Container</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Container</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Container</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span></code>

Then you can create a container which wraps a function which might throw an exception (together with its error handler):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Try</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Container</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> f</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Container</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> errorHandler</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> unknown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Container</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    andThen</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Try</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> E</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">errorHandler</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    unsafeRun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        try</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> catch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (e) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">errorHandler</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Then you can write programs using these containers:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchSomeResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> PromiseIO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processResponse</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">response</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span></span>
<span class="line"><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold">    new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'OK'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> response))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ERR'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> program </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fetchSomeResponse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(processResponse)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">t</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRunTry</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">andThen</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">io</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (io </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeRun</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The next article contains a few examples and explains the above in bloody details, using TypeScript and a (semi-)real-world problem and a step-by-step approach to arrivin at the above concepts. It also introduces few more of those containers so you can actually go out and understand some (if not most) of the real-world applications made with functional paradigm. Or even build your own!

.gitignore is not ignoring urn:uuid:5ee372fe-3a03-524e-b2ff-b8bf7c0eeab5 2022-05-11T00:00:00Z 2022-05-11T00:00:00Z .gitignore is not ignoring Artem Shubovych

This is going to be a very short blog. I have been struggling with this issue for few days now - having a seemingly valid .gitignore file which does not make Git ignore any of the files.

The .gitignore file contents:

<code class="language-git">node_modules

**/*.bundle.js
*.log

*compiled-proto*
*compiled-bundle*
</code>

Running git status :

<code>$ git st
On branch master
Untracked files:
  (use "git add &#x3C;file>..." to include in what will be committed)
        node_modules/
        test1/flatbuffers-compiled-proto/
        test5/index.bundle.js
        test5/test5-avro.bundle.js
        test5/test5-bson.bundle.js
        test5/test5-cbor.bundle.js
        test5/test5-flatbuffers-compiled-proto/
        test5/test5-flatbuffers-compiled.bundle.js
        test5/test5-messagepack.bundle.js
        test5/test5-protobuf-compiled-proto.js
        test5/test5-protobuf-compiled.bundle.js
        test5/test5-protobuf.bundle.js

nothing added to commit but untracked files present (use "git add" to track)
</code>

Weird, isn't it?

There is a command which checks if a given path (whatever you pass as a parameter to the command, so technically just a string) would be ignored by any of the rules in .gitignore file or not:

<code>git check-ignore --verbose &#x3C;path>
</code>

Let's run it on my repo:

<code>$ git check-ignore --verbose node_modules
</code>

No output means the path (in this case - node_modules ) will not be ignored. Which should not be the case - there's a rule as the first line of the .gitignore file, right?!

The issue seems to be somewhat hidden - the file was saved in the UTF16-LE encoding, since I have used PowerShell to initialize the file with echo 'node_modules' >> .gitignore :

And seems like the valid encoding for .gitignore file would be UTF-8 . Let's use VSCode itself to save it in UTF-8 instead and try it again:

<code>$ git check-ignore --verbose node_modules
.gitignore:1:node_modules       node_modules
</code>

That output tells us the rule in the first line, namely node_modules (no asterisks or slashes) ignores the path node_modules . Issue solved!

Distributed Erlang example urn:uuid:4bad37ad-6ba1-5288-b260-914c8ae38214 2022-04-04T00:00:00Z 2022-04-04T00:00:00Z Distributed Erlang example Artem Shubovych

As promised in my previous blog about Erlang , I continue on a journey to more practical Erlang examples.

This might sound super ambitious, but let us build a distributed database.

For sake of simplicity, let's make it a reduced version of Redis - a key-value distributed in-memory storage. Essentially, an over-engineered hashmap.

To draw some boundaries around this, let's focus on these key features:

  • simple CRUD actions - get, set and delete a value; this should operate on REST-like API:
    • get(&#x3C;key>) - get key value
    • set(&#x3C;key>) - use request body for value and associate the value with the key
    • delete(&#x3C;key>) - remove the key from the storage
  • running on multiple nodes (machines)
  • synchronizing the data between the nodes; this should support:
    • ability to rotate the nodes in the cluster (switch off nodes and add new ones randomly) without the loss of data
    • distributing the operations across the nodes to keep the data in sync

Sounds unbelievable, but with Erlang this is actually pretty simple. Erlang is actually a great choice for an application like this, since we do not have to worry about setting up the cluster and deal with communication protocols (as in how to pass data over the network between the nodes).

We will need a "main" process, which will take the requests from the users and pass them to the nodes. Each node will store its own copy of the data in memory. On startup, each new node will receive the copy of the data from the first available node. If no nodes are available - that means the cluster is fresh and we can safely assume the data is empty (or the cluster has died altogether and that state is unrecoverable).

Step 1: draw a circle

Start simple: let us have a simple application which starts a background process and responds to some commands. It could be as simple as ping - pong application - the background process waits for a ping message and responds with pong upon receiving one.

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">db_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn_link</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    register</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pong </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

This is a relatively simple application, but it has few quirks:

  • spawn_link/1 ( spawn_link(loop) ) - this function spawns a new background process and links it to the current one, so that once the current process stops, the linked process also stops
  • register/2 ( register(server, Pid) ) - registers a global (in the current module scope) symbol ( server in this case) and associates it with the process PID passed as the second parameter ( Pid in this case, the PID of the spawned process running the loop function)
  • the ping/0 function sends a message ( { ping, self() } tuple) containing the atom ping and current process' PID to the process registered as server ; it then starts waiting for any process to send a pong message to the current process, effectively blocking the current process until that message is received
  • the loop function responds to two messages:
    • { ping, Pid } - by sending pong message to the process with PID set in the Pid constant and running itself recursively (turning the entire loop/0 function into a while loop)
    • stop - by simply returning the ok atom and exiting (thus terminating the loop)

To run this application, start the Erlang shell with erl and type in few prompts:

<code>1> c(db_server).
{ok,db_server}
2> db_server:start().
ok
3> db_server:ping().
pong
</code>

The benefit of this architecture is that once we have an Erlang shell open and run the start/0 function, it will start the background process and exit immediately. But the background process will keep running and we will have the other functions available to interact with that process, without loosing the access to the Erlang shell.

This protocol also highlights the concurrent aspect of the application - we send the current process' PID to the callee and start listening for the messages from anywhere . Once we receive the message - we pass it to the other process. So the entire application is predominantly non-blocking and asynchronous in nature.

Step 2: draw a second circle

The application is surely awesome, but let's make it actually useful to any extent. We are designing a key-value storage, so why not to have one? Instead of just reacting to the ping message, we can have a map and have a simple API to set value, get value and delete a value from the map while keeping the map on the child process.

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">db_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn_link</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    register</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">put</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">remove</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

As you can see, there's nothing special going on here - all is quite simple. We start the background process with some initial data ( maps:new() ) and in the loop/1 function whenever we enter recursion, we pass the new version of the data to the recursive call. The only function which actually is blocking its execution until it receives a response from a callee is get/1 - we wait for the background process to send the value to the current process.

The interaction with this application could look like this:

<code>1> c(db_server).
{ok,db_server}
2> db_server:start().
ok
3> db_server:set(moo, -3.14).
ok
4> db_server:get(moo).
-3.14
5> db_server:delete(moo).
ok
6> db_server:get(moo).
none
</code>

Step 3: draw the rest of the owl

Now for the juicy bits: let us have a worker node, which will actually be a replica of the database. It is as simple as extracting the logic from loop/1 function to a separate module and having a new process being started on a new node, once we decide to add it to the cluster:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">put</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">remove</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

The db_server module needs few changes:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">db_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn_link</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([])</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    register</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    server </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            monitor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

The public API of the db_server module does not really change - there's a new function add_node/1 but that's about it - these exported (aka "public") functions only send messages to the server process.

The loop/1 function on the other hand has most changes - instead of sending message to a single process, it now distributes them across the processes stored in the Nodes constant. This constant is a list of tuples { NodeAdd, NodePid } where the NodeAddr (the first element of the tuple) is just to keep track of nodes added to the list (for debug purposes predominantly) and NodePid (the second element of the tuple) is what is actually used to communicate with the db_server process.

All the control messages ( get , set and delete ) are passed to all nodes from the Nodes list. Exception being the { get, Key, Pid } message - it only sends the message to the first node from the list. And since all the worker nodes are (supposed to be) just replicas of each other, it is sufficient.

So far this should work. Start the db_server node with

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> erl</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -sname</span><span style="color:#40A02B;--shiki-dark:#A6D189"> supervisor</span></span></code>

followed by the call to

<code>(supervisor@MACHINENAME)> c(db_server).
{ok,db_server}
(supervisor@MACHINENAME)> db_server:start().
ok
</code>

Then, add few nodes to the cluster. For that, the node must be running and must use the same naming convention as the supervisor (short name, set with -sname param to the erl or long name, set with the -name param to the erl ) - otherwise they won't see each other.

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> erl</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -sname</span><span style="color:#40A02B;--shiki-dark:#A6D189"> subnode1</span></span></code>

followed by

<code>(subnode1@MACHINENAME)> c(worker).
{ok,worker}
</code>

Note how you don't need to do anything on the worker node except compile the module. The supervisor node will start processes on that node itself.

Lastly, on the server node call

<code>(supervisor@MACHINENAME)> server:add_node(subnode1@MACHINENAME).
ok
</code>

The node name is printed out to the Erlang shell once you start erl with -sname or -name param provided. But you can also add io:format("Started node at ~s~n", node()) as the first statement in the loop/1 function in worker module - it will print out the node name to the Erlang shell once the function is started. You can then use it as a raw atom parameter to server:add_node/1 .

Now, the last piece to the system is keeping all the worker nodes in sync by copying the data from the first alive node to the new node once it is added to the supervisor.

To do so, we will need to utilize the net_adm module, which conveniently has the net_adm:ping/1 function, taking the node address and returning pond atom if the node is alive and is visible from the current node or pang otherwise. This way we can replace all the occurrences of the Nodes list in the db_server:loop/1 function with the list of alive nodes:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% supervisor</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> sets</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            monitor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

Now to get the data from the node, we will need an extra message to be supported by the worker module:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% worker</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">put</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">remove</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

This way when we want to add a new node to the cluster, we will need to first get the data from the first available node and then send it to the newly added node in the db_server module. But if there are no nodes alive, we want the maps:new() to be the new data:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% supervisor</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            monitor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

You may practice putting nodes on and off the running cluster, getting and setting the values at the same time. But occasionally you might stumble upon a db_server:get/1 function hanging. This is what happens when there are no alive nodes on the cluster. In order to fix this, we can simply add a check for that instead of blindly taking the first node from the AliveNodes list:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% supervisor</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> no_nodes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            monitor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

This will still not work however. The issue is that we only assign the value to the AliveNodes once we enter the db_server:loop/1 function. And that only happens after it processed a message. But the moment the value is actually needed is right before processing a message . See the difference? There might be a delay between processing (as in "receiving") a message and figuring the list of actually alive nodes because the process is blocked waiting for new messages.

One way to fix this is to move the AliveNodes assignment to each branch of the receive block:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% supervisor</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> no_nodes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            monitor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

Alternatively, we can utilize the after keyword which effectively implements a timeout mechanism:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% supervisor</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReceivedValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> no_nodes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            monitor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    after</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

This will make the receive expression of the db_server:loop/1 function check if there are any messages in the internal message inbox (aka message queue) associated with the current function. And if there are no messages after 0 (as in this case) time since the check started - the code in the corresponding matching expression will be executed. In our scenario, we figure the new list of alive nodes and restart the loop function. This way the time the process is sitting blocked waiting for messages is bare minimal.

On the other hand, if you look carefully at all those receive statements within the loop function, you might just notice... that you don't need them in fact - the worker nodes might just communicate with each other! So instead of sending self() PID to each worker node (for ex. for get message or get_all message), you can just send the received node PID (which is a part of the message) to the worker node. This will make the code highly asynchronous:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% supervisor</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    AliveNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> net_adm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pong </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> no_nodes </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> worker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            monitor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">process</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewNodes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodeAddr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AliveNodes </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FirstNodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NodePid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> got_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewNodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

This will need a tiny adjustment to the worker module (to support that { got_all, Data } messages), but the benefits are more than worth it!

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% worker</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">put</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            NewData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">remove</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> get_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> got_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewData </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">NewData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

Wrap-up

The cherry on top of this cake would be to create an actual REST API (or any non-Erlang API for that matter) so that this database could be used from the outside world without starting an Erlang shell. But I'd rather save it for a later blog.

For now you can actually plug and unplug nodes from the cluster, and while there is at least one node alive, the data integrity is guaranteed.

The highly asynchronous architecture of the solution allows for non-blocking calls all over the place.

For me, this is a great example on how to actually use Erlang!

The slightly built-up code is hosted on GitHub .

What is a Monad? urn:uuid:f33664ac-e5bf-5f42-b93c-81ba79568bb4 2021-07-02T00:00:00Z 2021-07-02T00:00:00Z What is a Monad? Artem Shubovych

What is a monad?

There is a talk by Gilad Bracha, "Deconstructing functional programming" . This is a very good introduction to functional programming, monads included.

As per that talk, think about monad as a class like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">  @Immutable</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> final</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> A</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flatMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Just rename FlatMappable to Monad and there you go.

Now, if you want more Haskell naming (gonna implement it in C++ for more correct syntax):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">template</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">typename</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cass Monad </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  static</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Monad</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Monad</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  template </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">typename</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Monad</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> operator</span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">function</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Monad</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">B</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  Monad</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">m_a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  immutable</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m_a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Essentially, renaming constructor to return and flatMap to operator>>=

Also, in terms of Mappable vs FlatMappable :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> final</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> A</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  Mappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  Mappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> map</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Mappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Flattable</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  Flattable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> super</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  Flattable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> flatten</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a instanceOf </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Flattable</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatten</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Flattable</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> super</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flatMap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FlatMappable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> map</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatten</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Why do we need monads?

In order to preserve purity of programs in functional programming languages, you can not have side-effects in your program.

But if you need interaction with outside systems (IO, database, system clock, random number generator, etc.), you will need to somehow make these operations without side-effects.

So you write your entire program as a description of a workflow (e.g. how data will be processed). Basically your program becomes a chain of functions calling other functions. No waiting for events, nothing like that.

Then, when you run your program, "at the execution edge" (aka "event horizon"), just before your program finishes, the runtime will do all the "unsafe" (or rather "impure") operations (interaction with IO, system clock, etc.) and will feed all the input to your functions, take the output and modify "the state of the world outside".

Where are monads on this? Monads are basically just wrappers around other values, telling the runtime what to do. So that your code is still pure and all the impure side-effects will be eventually handled by runtime.

For example, reading from STDIN would be something like IO&#x3C;String> - a monad, whose value will be provided eventually. So your program will be defined as a function something like

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] input)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  input.map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> printLn(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Hello, ${name}"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

As you can see, main is a function which simply returns another IO[String] by mapping a monad parameter.

When you run it, the program will effectively stop until the IO[String] input parameter is filled with value. When the value will be provided, runtime will execute the rest of the code (the map { ... } part).

irrPaint3d urn:uuid:9bd68dd9-fe68-5125-b698-67885e8761c5 2021-05-04T00:00:00Z 2021-05-04T00:00:00Z

Recently I was reviving some of my old projects. And to my surprise, there were some people actually interested in those! That was a good enough reason for me to revise the old pet projects of mine and exercise my skills (mostly in C++ though).

One really interesting project I had back in the day was irrPaint3d. It all started as an idea for my B.Sc. thesis and the ultimate goal was to enable users paint 3D objects and immediately see the results in realtime, in 3D.

This is a no unique feature nowadays, but back in 2013, to my knowledge, the only way to texture 3D models was to either unwrap them to UV maps and then paint the textures in graphics editor (such as Gimp or Paint.NET) or to use a proprietary software, 3D Coat.

Unwrapping 3D model texture in Blender in 2013

And a mere idea of implementing such tool myself was quite exciting. Darn, if I managed to implement it back in 2013, my thesis would shine among best thesises in my uni!

Long story short, I have failed with that. And now, after spending just few days on this, I am happy to say I have achieved something with yet another glorious pet project revival:

Revised 3D model painting

And it actually allows to paint the model in 3D, displaying the results in real-time!

A bit of history on how I got there and maths behind the solution under the cut.

Artem Shubovych

Recently I was reviving some of my old projects. And to my surprise, there were some people actually interested in those! That was a good enough reason for me to revise the old pet projects of mine and exercise my skills (mostly in C++ though).

One really interesting project I had back in the day was irrPaint3d. It all started as an idea for my B.Sc. thesis and the ultimate goal was to enable users paint 3D objects and immediately see the results in realtime, in 3D.

This is a no unique feature nowadays, but back in 2013, to my knowledge, the only way to texture 3D models was to either unwrap them to UV maps and then paint the textures in graphics editor (such as Gimp or Paint.NET) or to use a proprietary software, 3D Coat.

Unwrapping 3D model texture in Blender in 2013

And a mere idea of implementing such tool myself was quite exciting. Darn, if I managed to implement it back in 2013, my thesis would shine among best thesises in my uni!

Long story short, I have failed with that. And now, after spending just few days on this, I am happy to say I have achieved something with yet another glorious pet project revival:

Revised 3D model painting

And it actually allows to paint the model in 3D, displaying the results in real-time!

A bit of history on how I got there and maths behind the solution under the cut.

A brief history

Back in the day I have put too little thought into the project so I ended up trying to implement LSCM algorithm to unwrap 3D models. And after numerous failures I came up with my own, very simple algorithm to unwrap models and that made my B.Sc. thesis.

The algorithm was a simple system of numerous circle equations following the logic of pinning down a vertex from a triangle on 2D plane at point (0, 0) and figuring out the 2D coordinates of the other two vertices using the lengths of the triangle edges in 3D, using two circles, with centres at the pinned point ( (0, 0) ) and radiuses equal to triangle edges' lengths. The circles would overlap in two points, and both are candidates for the other two triangle' verices mapping:

The idea behind my unwrapping algorithm

The algorithm... worked... in some cases:

Sample algorithm result, unwrapped cube

I did try to understand the concept of barycentric coordinates, but that is something completely different to what I imagined, apparently:

My previous understanding of barycentric coordinates

The maths behind

With my new approach, I took an idea from the enormously cool introduction to computer graphics and the math underneath by One Lone Coder . The idea itself is rather trivial: any vector could be represented as a sum of two other (not necessarily orthogonal) vectors (plus a condition that the angle between the two should not be 180 degrees).

Vector as a sum of other vectors

In the example above, vector p could be represented as a sum of vectors a and b , each multiplied by certain coefficients: p = u*a + v*b .

And the dimensions of the vectors do not matter - this logic will work just as well in 3D as in 2D.

Now, if we have a triangle in 3D, ABC and a point inside that triangle P , we can represent the vector AP as a sum of vectors AB and AC multiplied by some coefficients, u*AB + v*AC = AP .

It is only the matter of finding those coefficients, u and v . Luckily, this could be done with a system of three linear equations with just two variables:

<code>ax * u + bx * v = px
ay * u + by * v = py
az * u + bz * v = pz
</code>

where

  • vector AB &#x3C;=> a(ax, ay, az)
  • vector AC &#x3C;=> b(bx, by, bz)
  • vector AP &#x3C;=> p(px, py, pz)

Simply using the substitution, we can first express u as a function of v and then calculate v to then find u . The only bit here is that the multiplier of v must not be zero.

In C++ this looks like this (I am using Irrlicht for this application, so bare with irr:: namespaces):

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">S3DVertex A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// find A, B and C from the selected triangle</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// also collisionPoint is the point in question, inside the selected triangle</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df b </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df p </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> collisionPoint </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// au + bv = p</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    u </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    u </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    u </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    throw</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Invalid input - zero basis vector"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now the last bit of the maths: given the points of a selected triangle all have their texture coordinates (hence using irr::video::S3DVertex ), how do we find the texture coordinates of a given point P ? Simple: by applying the same vector maths to the texture coordinates: we can represent a given triangle in 2D space of texture coordinates and using the vectors AB , AC and AP and the multipliers u and v which we have just obtained from 3D space, we can "interpolate" the texture coordinates of vector AP :

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector2df t2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector2df t1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TCoords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector2df uvCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TCoords </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t1 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t2 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The rest is just rendering and drawing on a texture. The full version of the project is available on GitHub .

Irrlicht application template urn:uuid:779db6f8-bbc2-5070-84b3-7753460b152f 2021-05-02T00:00:00Z 2021-05-02T00:00:00Z

Often when I start revising my old applicaitons with Irrlicht engine, I do few things very similarly. Especially when the application contains GUI and uses Irrlicht tools for it.

This is mostly due to the extremely outdated nature of Irrlicht itself. There are all sorts of things in it like the lack of 4K monitors support, the use of a very obscure font, sample applications being a simple yet messy single CPP files, etc.

The common things I do include:

  • using new C++ standard features such as:
    • shared pointers
    • automatic type inference
    • standard containers
    • C++-style string operations
  • setting the new font for GUI, adopted to higher screen resolutions
  • using CMake to build the project and vcpkg to manage dependencies
  • utilizing object-oriented approach
  • moving the classes to separate header and CPP files

In this blog I describe in bloody detail what I do and why.

Artem Shubovych

Often when I start revising my old applicaitons with Irrlicht engine, I do few things very similarly. Especially when the application contains GUI and uses Irrlicht tools for it.

This is mostly due to the extremely outdated nature of Irrlicht itself. There are all sorts of things in it like the lack of 4K monitors support, the use of a very obscure font, sample applications being a simple yet messy single CPP files, etc.

The common things I do include:

  • using new C++ standard features such as:
    • shared pointers
    • automatic type inference
    • standard containers
    • C++-style string operations
  • setting the new font for GUI, adopted to higher screen resolutions
  • using CMake to build the project and vcpkg to manage dependencies
  • utilizing object-oriented approach
  • moving the classes to separate header and CPP files

In this blog I describe in bloody detail what I do and why.

Application structure

First of all, applicaiton structure is:

  1. main.cpp - only instantiates the Application class and calls its run() method (the only public API of the Application class)
  2. Application class - has two purposes:
  3. initialize Irrlicht sub-systems (device, GUI, renderer, scene manager, etc.)
  4. runs the main application loop, but delegate all the business logic to the ApplicationDelegate class
  5. ApplicaitonDelegate - does a bit more than Application :
  • loads resources
  • resets default GUI settings
  • creates the camera
  • defines (user) events callbacks (handling business logic of the application)
  • handles every frame update (rendering, third-party systems' updates such as physics, AI, math, etc.)
  1. IrrlichtEventReceiver - intercepts Irrlicht-specific events and delegates the execution to a corresponding event handler from ApplicationDelegate

For my ShootThem! game I have also defined game state in a somewhat interesting manner, uncommon for game development - utilizing the principles of Redux from front-end, since it made sense to me back in the day - user and application trigger events, event receiver delegates them to the application delegate, which returns a new state and passes the state back to the store, application uses the state to render things on the screen.

For a more complicated application it might be easier to use the state machine approach instead, which is a common approach in gamedev.

Build system

Back to the topic of the application template, it is, again, a common practice in a modern (C++) world to use some sort of a build system and dependency manager. The reason being the simplicity of setup and deploy, abstraction from dependencies' build process, ease of distribution. Makefiles do not really play well with Windows-based systems, for example. Whilst vcproj / mssys build is hard to get right on Unix-based systems. And handling dependencies is a pain in the neck when dependencies themselves have different build processes and transient dependencies.

Hence I stick with CMake for the overall application build process (although I honestly hate it, since it is so bloated and cumbersome) and vcpkg to get dependencies for my applications.

CMake configuration

The main entry point of an application build process is the CMakeLists.txt file, which defines how the application is built.

Following the best practices collected all over the world (conference talks, recent blogs, etc. - the existing documentation for CMake is horrible in that regard it shows off the bad practices and utilizes the outdated approaches), her is what I came up with:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.16 FATAL_ERROR)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(myapplication VERSION 1.0.1 LANGUAGES CXX)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME myapplication)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCES</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/main.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/ApplicationDelegate.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/ApplicationDelegate.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/IrrlichtEventReceiver.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/IrrlichtEventReceiver.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/Application.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/Application.cpp"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCES})</span></span></code>

VCPKG configuration

VCPKG can use the configuration file when invoked with params swithing it to the manifest mode . I am unsure why this is not the default mode until now, but it is what it is.

Anyways, the vcpkg.json file looks like this:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">$schema</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "myapplication"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">version-string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "0.1.0"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">dependencies</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "irrlicht"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

When invoked from a command line, vcpkg will tell you what you should add to your CMakeLists.txt file to find the package you've just installed:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> vcpkg</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> irrlicht</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Computing</span><span style="color:#40A02B;--shiki-dark:#A6D189"> installation</span><span style="color:#40A02B;--shiki-dark:#A6D189"> plan...</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">The</span><span style="color:#40A02B;--shiki-dark:#A6D189"> following</span><span style="color:#40A02B;--shiki-dark:#A6D189"> packages</span><span style="color:#40A02B;--shiki-dark:#A6D189"> are</span><span style="color:#40A02B;--shiki-dark:#A6D189"> already</span><span style="color:#40A02B;--shiki-dark:#A6D189"> installed:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    irrlicht[core]:x86-windows</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1.8.4-10</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Package</span><span style="color:#40A02B;--shiki-dark:#A6D189"> irrlicht:x86-windows</span><span style="color:#40A02B;--shiki-dark:#A6D189"> is</span><span style="color:#40A02B;--shiki-dark:#A6D189"> already</span><span style="color:#40A02B;--shiki-dark:#A6D189"> installed</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Total</span><span style="color:#40A02B;--shiki-dark:#A6D189"> elapsed</span><span style="color:#40A02B;--shiki-dark:#A6D189"> time:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 214.7</span><span style="color:#40A02B;--shiki-dark:#A6D189"> us</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">The</span><span style="color:#40A02B;--shiki-dark:#A6D189"> package</span><span style="color:#40A02B;--shiki-dark:#A6D189"> irrlicht:x86-windows</span><span style="color:#40A02B;--shiki-dark:#A6D189"> provides</span><span style="color:#40A02B;--shiki-dark:#A6D189"> CMake</span><span style="color:#40A02B;--shiki-dark:#A6D189"> targets:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    find_package(irrlicht</span><span style="color:#40A02B;--shiki-dark:#A6D189"> CONFIG</span><span style="color:#40A02B;--shiki-dark:#A6D189"> REQUIRED</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    target_link_libraries(main</span><span style="color:#40A02B;--shiki-dark:#A6D189"> PRIVATE</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Irrlicht</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Just follow these instructions and add those lines to the CMakeLists.txt file:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.16 FATAL_ERROR)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(myapplication VERSION 1.0.1 LANGUAGES CXX)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME myapplication)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCES</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/main.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/ApplicationDelegate.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/ApplicationDelegate.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/IrrlichtEventReceiver.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/IrrlichtEventReceiver.cpp"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/Application.h"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "src/Application.cpp"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCES})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(irrlicht CONFIG REQUIRED)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} PRIVATE Irrlicht)</span></span></code>

Building

The only trick to building the project with vcpkg is the invocation of CMake:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cmake</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -B</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -S</span><span style="color:#40A02B;--shiki-dark:#A6D189"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189">  -DCMAKE_TOOLCHAIN_FILE=C:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\U</span><span style="color:#40A02B;--shiki-dark:#A6D189">sers</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\m</span><span style="color:#40A02B;--shiki-dark:#A6D189">yuser</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\v</span><span style="color:#40A02B;--shiki-dark:#A6D189">cpkg</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\v</span><span style="color:#40A02B;--shiki-dark:#A6D189">cpkg</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\s</span><span style="color:#40A02B;--shiki-dark:#A6D189">cripts</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\b</span><span style="color:#40A02B;--shiki-dark:#A6D189">uildsystems</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\v</span><span style="color:#40A02B;--shiki-dark:#A6D189">cpkg.cmake</span></span></code>

This will download all the dependencies specified in the vcpkg.json file and generate the project for the corresponding build system.

The build process then is straightforward:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cmake</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --build</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build</span></span></code>

Source

The sources for the application units mentioned above are:

main.cpp

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Application.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;memory></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">unique_ptr</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Application</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> app </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    app</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Application.h

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#pragma</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> once</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "ApplicationDelegate.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "IrrlichtEventReceiver.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;irrlicht.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;iostream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;string></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IrrlichtDevice</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IVideoDriver</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneManager</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIEnvironment</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shared_ptr</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ApplicationDelegate</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">unique_ptr</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IrrlichtEventReceiver</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Application.cpp

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Application.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createDevice</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EDT_OPENGL</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dimension2d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">u32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1024</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 768</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cerr </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Could not initialize video device</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setWindowCaption</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">L"irrPaint3D"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    driver </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getVideoDriver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    smgr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSceneManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    guienv </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getGUIEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    applicationDelegate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_shared</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    eventReceiver </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make_unique</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IrrlichtEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">eventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isWindowActive</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isWindowFocused</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isWindowMinimized</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

ApplicationDelegate.h

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#pragma</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> once</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;fstream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;iostream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;memory></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;queue></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;sstream></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;string></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;irrlicht.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ApplicationDelegate</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IrrlichtDevice</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> _device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // event callbacks</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> quit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initGUI</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loadGUI</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> resetFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getElementByName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getElementByName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IrrlichtDevice</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IVideoDriver</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneManager</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIEnvironment</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ICameraSceneNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> camera</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

ApplicationDelegate.cpp

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "ApplicationDelegate.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IrrlichtDevice</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSceneManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getGUIEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getVideoDriver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    camera</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    camera </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addCameraSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    initGUI</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">initGUI</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    loadGUI</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    resetFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    createToolbar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loadGUI</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loadGUI</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/gui.xml"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getElementByName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getElementByName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRootGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getElementByName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">queue</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIElement</span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    queue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">queue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentElement </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> queue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">front</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        queue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentElementName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">currentElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentElementName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> child </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getChildren</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            queue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">child</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">resetFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIFont</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> font </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/calibri.xml"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSkin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">font</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">quit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">closeDevice</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">beginScene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 200</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 200</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 200</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endScene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Worth mentioning the two helpers I have added to this class:

  • getElementByName(std::string name)
  • getElementByName(std::string name, irr::gui::IGUIElement* parent) ,

They are really a big help when working with GUI designed with out-of-the-box GUIEditor and has to do with Irrlicht specifics: any given GUI element in Irrlicht can have both ID (integer) or name (string). In the GUI editor you can specify both, but what you will end up with is trying to remember all those integers when both designing a GUI in the editor and later, when you write code for that GUI.

One way to do it properly would be to automatically generate a mapping between GUI elements' IDs and names and then use it in the application, but out-of-the-box GUI editor is not that sophisticated and you will have to do it by hand by analyzing the XML. That's where the issue lies: if your GUI element does not have a name - good luch figuring out a name for it - was it a button X or a button Z?

Hence I operate on elements' names. They are nothing more than strings. This is a suboptimal solution, since recursively traversing the whole GUI and comparing each element's string name to a given string is somewhat expensive, when done on every GUI event (think MouseMove event or something) or every frame (for whatever reason). But it gets the job done without the need to modify the GUIEditor itself.

One other tricky thing with the out-of-the-box GUIEditor is the texture for GUI elements - the default value for texture attribute in the editor is -1 , whatever that means so one must specify a relative path to a texture by hand and hope editor won't crash (since it will try to load the file, if it is not present in the working directory of editor - it will throw an unhandled exception and die). Hence I manually edit the GUI XML file and specify the paths to the textures after I'm done designing the GUI.

Also, since there is no out-of-the-box SaveFileDialog component (which is weird, since there is a IGUIFileOpenDialog , which could be easily extended to support opening files functionality), I often have to implement it by hand like described by someone on the forums years ago ( 2008 to be exact). See the details of its implementation below .

The other detail is that the default font provided by Irrlicht is extremely old and looks ugly on modern high-resolution screens. Irrlicht does not work with TTF or other font types out-of-the-box, but uses a bitmap with all the supported characters instead. I converted one of the fonts available in my Windows system, Calibri , to a font map (PNG + XML file combo, consumable by Irrlicht) with the out-of-the-box FontTool provided by Irrlicht, by selecting the maximum available file dimensions, reasonable font size ( 18px in my case) and enabling the alpha for the font map (otherwise all the GUI elements will have ugly black background):

FontTool configuration

Then the resetFont method of the ApplicationDelegate uses the new font for the whole application:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIFont</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> font </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/calibri.xml"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">guienv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSkin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">font</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Note that you must store both PNG and XML files under the same directory (or specify the relative path to the font map (PNG) in the XML file by hand).

It makes a significant difference in the looks of an application:

Before:

FontTool configuration

After:

FontTool configuration

IrrlichtEventReceiver.h

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#pragma</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> once</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "ApplicationDelegate.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;memory></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;irrlicht.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IrrlichtEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IEventReceiver</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    IrrlichtEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">shared_ptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ApplicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    bool</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">SEvent</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shared_ptr</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ApplicationDelegate</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

IrrlichtEventReceiver.cpp

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "IrrlichtEventReceiver.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IrrlichtEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">IrrlichtEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shared_ptr</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ApplicationDelegate</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">move</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_applicationDelegate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">bool</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> IrrlichtEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">SEvent</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_KEY_INPUT_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // handling CTRL+S</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KeyInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KEY_KEY_S </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KeyInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Control</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // applicationDelegate->saveSomething();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_MOUSE_INPUT_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // handling mouse movement</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Event </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMIE_MOUSE_MOVED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // applicationDelegate->onMouseMoveSomething();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Copying resources

One more tricky thing with these applications is how to copy the resources (fonts, 3D assets, etc.) to the executable directory. In CMake this could be done by using this trick (so that it copies files at build time as opposed to generation time ):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_custom_command</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">TARGET</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${EXECUTABLE_NAME} POST_BUILD </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">COMMAND</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${CMAKE_COMMAND} -E copy_directory  ${CMAKE_CURRENT_LIST_DIR}/media $&#x3C;TARGET_FILE_DIR:${EXECUTABLE_NAME}>/media)</span></span></code>

Bonus: SaveFileDialog

This is something I implement in my own editors (like the level editor for ShootThem! ). As mentioned above, this implementation takes its roots at this forum post by @pera from 2008, which, is a fork itself of a code by @MolokoTheMole from 2007 , apparently.

SaveFileDialog.h

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#pragma</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> once</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;codecvt></span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for converting wstring to string</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;xlocbuf></span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for converting wstring to string</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;memory></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;string></span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;irrlicht.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32 SAVE_FILE_DIALOG_WIDTH </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 350</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32 SAVE_FILE_DIALOG_HEIGHT </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 250</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIFileOpenDialog</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! constructor</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> wchar_t*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIEnvironment</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IGUIElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            bool</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> restoreCWD</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">char_type</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> startDir</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! destructor</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ~SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! returns the filename of the selected file. Returns NULL, if no file was selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> wchar_t*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! Returns the filename of the selected file. Is empty if no file was selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getFileNameP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! Returns the directory of the selected file. Returns NULL, if no directory was selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! Returns the directory of the selected file converted to wide characters. Returns NULL if no directory was selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> wchar_t*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getDirectoryNameW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! called if an event happened.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">SEvent</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! draws the element and its children</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">protected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! Ensure filenames are converted correct depending on wide-char settings</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> pathToStringW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">stringw</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! fills the listbox with files.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fillListBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! sends the event that the file has been selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sendSelectedEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">EGUI_EVENT_TYPE</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //! sends the event that the file choose process has been canceled</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sendCancelEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">position2d</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DragStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path FileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stringw FileNameW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path FileDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path FileDirectoryFlat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stringw FileDirectoryFlatW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path RestoreDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path StartDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIButton</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIButton</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OKButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIButton</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CancelButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIListBox</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIEditBox</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIElement</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> EventParent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IFileSystem</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IFileList</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Dragging</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

SaveFileDialog.cpp

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "SaveFileDialog.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! constructor</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> wchar_t</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIEnvironment</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIElement</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32 id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> restoreCWD</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">char_type</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> startDir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        : </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">IGUIFileOpenDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parent </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRootGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 SAVE_FILE_DIALOG_WIDTH</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parent </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRootGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 SAVE_FILE_DIALOG_HEIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parent </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRootGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 SAVE_FILE_DIALOG_WIDTH</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> SAVE_FILE_DIALOG_WIDTH</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">parent </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parent </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRootGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 SAVE_FILE_DIALOG_HEIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> SAVE_FILE_DIALOG_HEIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          Dragging</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#ifdef</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _DEBUG</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    IGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDebugName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"SaveFileDialog"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#endif</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileSystem </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">grab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">restoreCWD</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            RestoreDirectory </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWorkingDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startDir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            StartDirectory </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> startDir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">changeWorkingDirectoryTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startDir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUISpriteBank</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sprites </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SColor </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUISkin</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSkin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        sprites </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSpriteBank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDC_WINDOW_SYMBOL</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32 buttonw </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDS_WINDOW_BUTTON_WIDTH</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32 posx </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> RelativeRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buttonw </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CloseButton </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">posx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> posx </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buttonw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> buttonw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">            L""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            skin </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getDefaultText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDT_WINDOW_CLOSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> L"Close"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSubElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setTabStop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sprites</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSpriteBank</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sprites</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSprite</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGBS_BUTTON_UP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getIcon</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDI_WINDOW_CLOSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSprite</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGBS_BUTTON_DOWN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getIcon</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDI_WINDOW_CLOSE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAlignment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">grab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    OKButton </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">RelativeRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 80</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> RelativeRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 50</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getDefaultText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDT_MSG_BOX_OK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> L"OK"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    OKButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSubElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    OKButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAlignment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    OKButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">grab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CancelButton </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">RelativeRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 80</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 55</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> RelativeRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 75</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getDefaultText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDT_MSG_BOX_CANCEL</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> L"Cancel"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CancelButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSubElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CancelButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAlignment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CancelButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">grab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileBox </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addListBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 55</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> RelativeRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 90</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 230</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">            true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSubElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAlignment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">grab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileNameText </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addEditBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> RelativeRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 90</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 50</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">            true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setSubElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAlignment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_LOWERRIGHT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGUIA_UPPERLEFT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">grab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setTabGroup</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fillListBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! destructor</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#179299;--shiki-dark:#81C8BE">~</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        CloseButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">OKButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        OKButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CancelButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        CancelButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // revert to original CWD if path was set in constructor</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">RestoreDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">changeWorkingDirectoryTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">RestoreDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! returns the filename of the selected file. Returns NULL, if no file was selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> wchar_t*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileNameW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFileNameP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! Returns the directory of the selected file. Returns NULL, if no directory was selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileDirectoryFlat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> wchar_t*</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getDirectoryNameW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileDirectoryFlatW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    pathToStringW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileNameW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileDirectory </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileDirectoryFlat </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flattenFilename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileDirectoryFlat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    pathToStringW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileDirectoryFlatW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileDirectoryFlat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! called if an event happened.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">bool</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">SEvent</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isEnabled</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        switch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_GUI_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            switch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_ELEMENT_FOCUS_LOST</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Dragging </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_BUTTON_CLICKED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Caller </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CloseButton </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Caller </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CancelButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    sendCancelEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    remove</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Caller </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OKButton</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        sendSelectedEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_FILE_SELECTED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        remove</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        sendSelectedEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_DIRECTORY_SELECTED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_LISTBOX_CHANGED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32 selected </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSelected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFullFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFullFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_LISTBOX_SELECTED_AGAIN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32 selected </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSelected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFullFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">changeWorkingDirectoryTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        fillListBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFullFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_EDITBOX_CHANGED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Caller </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_EDITBOX_ENTER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Caller </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">changeWorkingDirectoryTo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        fillListBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    else</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                        setFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            default</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_MOUSE_INPUT_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            switch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMIE_MOUSE_WHEEL</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMIE_LMOUSE_PRESSED_DOWN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                DragStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                DragStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Dragging </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMIE_LMOUSE_LEFT_UP</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Dragging </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMIE_MOUSE_MOVED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isLeftPressed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Dragging </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Dragging</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                    // gui window should not be dragged outside its parent</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UpperLeftCorner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UpperLeftCorner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LowerRightCorner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LowerRightCorner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                            return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    move</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">position2d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DragStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                            event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DragStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    DragStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    DragStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            default</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> IGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! draws the element and its children</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IsVisible</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUISkin</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSkin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rect</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s32</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rect </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AbsoluteRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    rect </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw3DWindowBackground</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDC_ACTIVE_BORDER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AbsoluteClippingRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UpperLeftCorner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LowerRightCorner</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDS_WINDOW_BUTTON_WIDTH</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIFont</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> font </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFont</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDF_WINDOW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">font</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            font</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDC_ACTIVE_CAPTION</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">                    false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AbsoluteClippingRect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    IGUIElement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">draw</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pathToStringW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">stringw</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">path</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#ifndef</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _IRR_WCHAR_FILESYSTEM</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">wstring_convert</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">codecvt_utf8_utf16</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">wchar_t</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> wstringConverter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> wstringConverter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from_bytes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#endif</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! fills the listbox with files.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fillListBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUISkin</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> skin </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Environment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSkin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileSystem </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileBox </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">clear</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    FileList </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createFileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stringw s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u32 i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFileCount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            pathToStringW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFileName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            FileBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addItem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    skin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getIcon</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDI_DIRECTORY </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGDI_FILE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        setDirectoryName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">FileSystem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getWorkingDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        pathToStringW</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FileDirectory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        FileNameText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! sends the event that the file has been selected.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sendSelectedEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">EGUI_EVENT_TYPE</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SEvent event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_GUI_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Caller </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Element </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//! sends the event that the file choose process has been cancelled</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> SaveFileDialog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sendCancelEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SEvent event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_GUI_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Caller </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Element </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> nullptr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GUIEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EGET_FILE_CHOOSE_DIALOG_CANCELLED</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Outro

This is about everything I wanted to share. This template should set you up in few-ish minutes so that you can start implementing the actual application logic instead of wondering why there are some missing references for linker or some nuisance like those.

Strongly-typed front-end urn:uuid:f378e87b-4c77-53fc-bfa8-b4ae6567900e 2021-04-19T00:00:00Z 2021-04-19T00:00:00Z Strongly-typed front-end Artem Shubovych
Serial experiments Lain

In this little research project I describe my journey through a series of experiments trying out a number of technologies and clashing them against each other.

Strongly-typed front-end: introduction urn:uuid:dac9987e-8d7a-5948-9a7d-1a1d8172db60 2021-04-19T00:00:00Z 2021-04-19T00:00:00Z Strongly-typed front-end: introduction Artem Shubovych

Contents

  1. Introduction (you are here)
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

In this little research project I describe my journey through a series of experiments trying out a number of technologies and clashing them against each other.

I have always questioned the real value all those languages that compile to JS, especially TypeScript or Flow, give you.

So I have asked Atlassian front-enders a question:

I need your opinions for my research: what benefits does TypeScript (or Flow, depending on your camp) give you? why do you use it?

The answers I have received varied but the common themes were:

  • we like types! 😍
  • less errors
  • easier refactoring
  • tools & IDEs integration (mainly for code navigation and autocomplete)
  • self-documented or more readable code

The issues I see with TypeScript and Flow are bit closer to the real world:

  • they catch way too few errors - unless your whole project (including 3rd party dependencies) is using the thing correctly , you will see the errors whenever you end up in the layer between native JS and typed code
  • more often than not, error messages are either pointless or hard to read (see the examples below)

I do acknowledge the earlier you catch an error, the cheaper the fix would be. You have to put some effort into writing the typed code, but if it only catches a fraction of errors and only at compile time, then why all the hassle?

"Benefits" of TypeScript

Pointless errors

The most issues I have seen so far happen in what is considered an stdlib:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyClass</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyClass[] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'moo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> </span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'bar'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counts </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">has</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Map</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Here we are reducing a list of objects. TS is freaking out every time you are using Map (however, it is a natively supported type, IIRC) - calling map.get() will always produce T | undefined type, unless you explicitly tell TS the type is T by using the as operator:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ERROR: Object is possibly 'undefined'.</span></span></code>

Adding an explicit check does not have any effect:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">has</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">!==</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // TS does not give a damn: Object is possibly 'undefined'.</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

whereas

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // OK</span></span></code>

But the issue is: if you do not add the check, the value in fact might be undefined .

Flow has flaws here too:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/* @flow */</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyClass</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyClass[] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'moo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> </span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'bar'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counts </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">has</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">!==</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ERROR: Cannot perform arithmetic operation because undefined [1] is not a number. [unsafe-addition]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id) </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Map</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

But it provides a bit more context about the issue:

<code>    16:     acc.set(e.id, acc.get(e.id) + e.val);
                          ^ Cannot perform arithmetic operation because undefined [1] is not a number. [unsafe-addition]
        References:
        [LIB] ..//static/v0.135.0/flowlib/core.js:617:     get(key: K): V | void;
                                                                            ^ [1]
</code>

Both Flow and TS work fine if you extract the .get call result to a variable and add a check for undefined :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyClass</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyClass[] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'moo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> </span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'bar'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counts </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prevVal </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (prevVal </span><span style="color:#179299;--shiki-dark:#81C8BE">!==</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prevVal </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        acc</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Map</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Implementation-specific errors

In order to understand this error message, you have to know how enums are implemented in TypeScript:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">enum</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Figure</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  RECTANGLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  SQUARE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  CIRCLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Record</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Figure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  [Figure</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">RECTANGLE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">w</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> h</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> h</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  [Figure</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">CIRCLE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">PI</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ERROR: Property '1' is missing in type '{ 0: (w: number, h: number) => number; 2: (r: number) => number; }' but required in type 'Record&#x3C;Figure, Function>'.</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(area)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Enums in TS are backed by numbers, by default . In order for that error above to make sense, you have to provide some sort of a reasonable ( .toString() -backed) value for enum values:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">enum</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Figure</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  RECTANGLE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'RECTANGLE'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  SQUARE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SQUARE'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  CIRCLE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'CIRCLE'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Record</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Figure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  [Figure</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">RECTANGLE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">w</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> h</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> h</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  [Figure</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">CIRCLE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">PI</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // ERROR: Property 'SQUARE' is missing in type '{ RECTANGLE: (w: number, h: number) => number; CIRCLE: (r: number) => number; }' but required in type 'Record&#x3C;Figure, Function>'.</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(area)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Runtime is imperfect

You might have typed every single bit of your project and all the 3rd party dependencies. And you did it right. This still does not guarantee you won’t have Can not read property XXX of undefined or XXX is not a function at run time.

Type system won’t really save you, if you only have covered some of the use cases, but the user ended up in uncovered one:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> useState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> useCallback </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'react'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">enum</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  SQUARE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SQUARE'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  CIRCLE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'CIRCLE'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AREA</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Record</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Function</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  [Shape</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">SQUARE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">side</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> side </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> side</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  [Shape</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">CIRCLE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">PI</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> default</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> setShape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useState</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> setValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useState</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">number</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">area</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> setArea</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useState</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">number</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onShapeChanged </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useCallback</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ChangeEvent</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">HTMLSelectElement</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onValueChanged </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useCallback</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ChangeEvent</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">HTMLInputElement</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFloat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onSubmit </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useCallback</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setArea</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(AREA[shape](value))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">div</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select onChange</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option value</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Choose shape</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">Object</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">keys</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">AREA</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">).</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">shape</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">option</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> value</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input value</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onChange</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChanged</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onSubmit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Calculate area</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">div</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">></span></span>
<span class="line"><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">        Area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic">area</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

This is a quite simple application ( sandbox ), built on top of the previous example with enums and records in TypeScript.

There are at least two uncovered scenarios in this application, resulting in errors:

  1. when user does not select a shape and clicks “calculate”, the TypeError: AREA[shape] is not a function will be thrown
  2. when user types anything but number in the input, the value immediately becomes NaN ; if user then clicks “calculate”, an error won’t be thrown (since the app does not use the calculation result in any way), but the area calculated will also be NaN ; for this example this is fine, but imagine using the value further down the line in some financial calculations

This is a trivial synthetic example and the errors might be easy to spot and fix, but the important question is: did TypeScript help you find those errors?

If you set up TSLint, you might have some errors caught:

<code>Argument of type 'null' is not assignable to parameter of type 'Shape | (() => Shape)'.ts(2345)
Argument of type 'string' is not assignable to parameter of type 'SetStateAction&#x3C;Shape>'.ts(2345)
Type 'null' cannot be used as an index type.ts(2538)
</code>

Unless you do the right thing, you might end up fixing those scenarios. But instead, I often see solutions like these ( sandbox ):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> setShape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> useState</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> null</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setShape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setArea</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(shape </span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AREA[shape](value) </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Those solutions do solve a subset of errors, at a cost of readability and potential other errors.

There are no classes in JavaScript

Found this one recently, apparently TypeScript classes are same as JavaScript (ES6) classes:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">namespace</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TypeScriptIsGarbage</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> a</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> B</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // perfectly fine</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> b</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> A</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // perfectly fine</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">namespace</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TypeScriptIsJavaScript</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> enum</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Types</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Types</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">A </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Types</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">B </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> a</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Types</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Type 'Types.B' is not assignable to type 'Types.A'.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> b</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Types</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Type 'Types.A' is not assignable to type 'Types.B'.</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This one is actually quite serious, if your application relies on type safety and objective-oriented-design.

Try doing it in C# (which TS tries to inherit from, iirc) and yo'll get sane compile-time errors:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Main</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  A</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createA</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Cannot implicitly convert type `B` to `A`</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  B</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Cannot implicitly convert type `A` to `B`</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

IDE integration is awesome

Recently I had to use both Cypress and Jest in a project of mine. Cypress was used for E2E tests and Jest was used for unit-tests. And they both provide some sort of assertion framework (think all those expect() calls).

And apparently their definitions are different and are clashing, since my VSCode looks like this:

TS definitions errors in VSCode TS definitions errors in VSCode

Apparently, I needed two separate tsconfig.json files, for each specific set of tests to even compile the thing. Which is still not recognized by VSCode.

Errors can be found and eliminated early

The helpfulness of the error messages by TS compiler is far from perfect. And same holds for TSLint.

And in some cases (as with type checks), they are even completely missing, so good luck finding out why the application does not work.

It is possible to add a bunch of debugger statements, breakpoints and console.log() s to the code. But what is the benefit of that complex setup and extra overhead of typing every single line then?

Strongly-typed front-end: experiment 2, simple application, in Elm urn:uuid:ea07a576-2fd9-5379-80fe-cc7263075883 2021-04-19T00:00:00Z 2021-04-19T00:00:00Z

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

(Heavily over-opinionated statement) Elm forces you to handle error scenarios when writing the code.

Sandbox

This is pretty much a translation of a TypeScript code from above:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Main</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">..</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Browser</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Html</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> button</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> div</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> option</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html.Attributes</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html.Events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onClick</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> onInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- util</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> | </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculate</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Area</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculate</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Area</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape value =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  case shape of</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> pi * value * value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    </span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> value * value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    </span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- MAIN</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main =</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  Browser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.sandbox { init = init, update = update, view = view }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- MODEL</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type alias </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = { shape: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, value: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, area: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">init : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">init = { shape = "", value = 0, area = 0 }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- UPDATE</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  = </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  | </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  | </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">CalculateArea</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update msg model =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  case msg of</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { model | shape = shape }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { model | value = value }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      </span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    CalculateArea</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { model | area = </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">shape</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- VIEW</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape = </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  case shape of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    "circle" -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    "square" -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value = </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">withDefault</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 0 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toFloat</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">view : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">view model =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  div []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ select [ on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      option [ value "" ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Choose</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape" ], </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      option [ value "circle" ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">" ],</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      option [ value "square" ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">" ] ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    , input [ value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromFloat</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    , button [ on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Click</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> CalculateArea</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Calculate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area" ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    , div [] [ text </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> " ++ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromFloat</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">area</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span></code>

Note that it won’t compile:

<code>-- TYPE MISMATCH ----------------------------------------------- Jump To Problem

Something is off with the body of the `init` definition:

29| init = { shape = "", value = 0, area = 0 }
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The body is a record of type:

    { area : Float, shape : String, value : Float }

But the type annotation on `init` says it should be:

    Model
</code>
Artem Shubovych

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

(Heavily over-opinionated statement) Elm forces you to handle error scenarios when writing the code.

Sandbox

This is pretty much a translation of a TypeScript code from above:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Main</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">..</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Browser</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Html</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> button</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> div</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> option</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html.Attributes</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html.Events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onClick</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> onInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- util</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> | </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculate</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Area</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculate</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Area</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape value =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  case shape of</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> pi * value * value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    </span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> value * value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    </span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- MAIN</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main =</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  Browser</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.sandbox { init = init, update = update, view = view }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- MODEL</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type alias </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = { shape: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, value: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, area: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">init : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">init = { shape = "", value = 0, area = 0 }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- UPDATE</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  = </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  | </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  | </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">CalculateArea</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update msg model =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  case msg of</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { model | shape = shape }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { model | value = value }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      </span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    CalculateArea</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { model | area = </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">shape</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- VIEW</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape = </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  case shape of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    "circle" -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    "square" -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value = </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">withDefault</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 0 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toFloat</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">view : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Html</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">view model =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  div []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [ select [ on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ShapeChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      option [ value "" ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Choose</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape" ], </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      option [ value "circle" ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">" ],</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      option [ value "square" ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">" ] ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    , input [ value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromFloat</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ValueChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] []</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    , button [ on</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Click</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> CalculateArea</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ text "</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Calculate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area" ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    , div [] [ text </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> " ++ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromFloat</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">area</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span></code>

Note that it won’t compile:

<code>-- TYPE MISMATCH ----------------------------------------------- Jump To Problem

Something is off with the body of the `init` definition:

29| init = { shape = "", value = 0, area = 0 }
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The body is a record of type:

    { area : Float, shape : String, value : Float }

But the type annotation on `init` says it should be:

    Model
</code>

You can’t have a default value for a type (the way enums are implemented in Elm / Haskell / ML-like languages) that is outside of the type values' range. You have to either use a valid value or stick to something like Maybe :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> alias </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Model</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Shape</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">init </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Model</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">init </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- UPDATE</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ShapeChanged</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ValueChanged</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Float</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> CalculateArea</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Msg </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Model </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Model</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update msg model </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ShapeChanged shape </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ValueChanged value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CalculateArea </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">withDefault </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape model</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">-- VIEW</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> String </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just Circle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just Square</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChanged </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> String </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChanged value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ValueChanged </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">withDefault </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">toFloat value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span></code>

See how this simple fact changes the whole implementation. Not sure if that is a good news, though.

Now even with these changes the code won’t compile, since there is one code path uncovered - user selecting a value other than circle or square (the default one):

<code>-- MISSING PATTERNS -------------------------------------------- Jump To Problem

This `case` does not have branches for all possibilities:

54|>  case shape of
55|>    "circle" -> ShapeChanged (Just Circle)
56|>    "square" -> ShapeChanged (Just Square)

Missing possibilities include:

    _

I would have to crash if I saw one of those. Add branches for them!

Hint: If you want to write the code for each branch later, use `Debug.todo` as a
placeholder. Read &#x3C;https://elm-lang.org/0.19.1/missing-patterns> for more
guidance on this workflow.
</code>

Elm forces you to cover that path.

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> String </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Msg</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> </span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just Circle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Just Square</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged Nothing</span></span></code>

See how awesome error messages from Elm are and how they really help you figure out what the issues are and fix errors.

Strongly-typed front-end: experiment 2, simple application, in PureScript urn:uuid:e3ccf930-14f6-5691-853c-30f0e7cdea26 2021-04-19T00:00:00Z 2021-04-19T00:00:00Z

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

In PureScript world there are quite a few libraries for React. And all of them have terrible (or rather non-existent) documentation, so I had to use as much intuition as outdated and barely working code samples. In this case I have picked purescript-react-dom .

Initial application structure:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Control.Monad.Eff</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe.Unsafe (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromJust</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Nullable (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMaybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect.Console (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DOM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">window</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML.Document (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">body</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML.Types (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">htmlElementToElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML.Window (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">document</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.Node.Types (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Element</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM.Props </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Props</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Circle</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getShape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  writeState ctx { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getShape ((unsafeCoerce evt)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value) }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onCalculateAreaClicked ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readState ctx</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  writeState ctx { area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape value }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">areaCalculator </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createClass </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> } </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ctx </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readState ctx</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onChange (onShapeChanged ctx) ] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show value) ] []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onClick (onCalculateAreaClicked ctx) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Calculate area"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Area: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show area))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> container </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render ui</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  ui</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ReactElement</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ui </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createFactory areaCalculator {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  container</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eff</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Eff</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> (dom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> eff) Element</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  container </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> do</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    win </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> window</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    doc </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> document win</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    elt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> fromJust </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;$></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> toMaybe </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;$></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> body doc</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    return </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> htmlElementToElement elt</span></span></code>
Artem Shubovych

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

In PureScript world there are quite a few libraries for React. And all of them have terrible (or rather non-existent) documentation, so I had to use as much intuition as outdated and barely working code samples. In this case I have picked purescript-react-dom .

Initial application structure:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Control.Monad.Eff</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe.Unsafe (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromJust</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Nullable (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMaybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect.Console (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DOM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">window</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML.Document (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">body</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML.Types (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">htmlElementToElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.HTML.Window (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">document</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM.Node.Types (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Element</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM.Props </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Props</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Circle</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getShape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  writeState ctx { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getShape ((unsafeCoerce evt)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value) }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onCalculateAreaClicked ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readState ctx</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  writeState ctx { area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape value }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">areaCalculator </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createClass </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> spec { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> } </span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ctx </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> readState ctx</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onChange (onShapeChanged ctx) ] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show value) ] []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onClick (onCalculateAreaClicked ctx) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Calculate area"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">      DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Area: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show area))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> container </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render ui</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  ui</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ReactElement</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ui </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createFactory areaCalculator {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  container</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eff</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Eff</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> (dom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> eff) Element</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  container </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> do</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    win </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> window</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    doc </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> document win</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    elt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> fromJust </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;$></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> toMaybe </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;$></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> body doc</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    return </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> htmlElementToElement elt</span></span></code>

Immediately the flaws of the infrastructure come out:

<code>$ spago build                                                                                                                                                                                                                                           1 ↵
Error 1 of 8:

  in module Main
  at src/Main.purs:5:1 - 5:25 (line 5, column 1 - line 5, column 25)

    Module Control.Monad.Eff was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.

Error 2 of 8:

  in module Main
  at src/Main.purs:8:1 - 8:36 (line 8, column 1 - line 8, column 36)

    Module Data.Maybe.Unsafe was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.

Error 3 of 8:

  in module Main
  at src/Main.purs:14:1 - 14:19 (line 14, column 1 - line 14, column 19)

    Module DOM was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.

Error 4 of 8:

  in module Main
  at src/Main.purs:15:1 - 15:25 (line 15, column 1 - line 15, column 25)

    Module DOM.HTML was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.

Error 5 of 8:

  in module Main
  at src/Main.purs:16:1 - 16:32 (line 16, column 1 - line 16, column 32)

    Module DOM.HTML.Document was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.

Error 6 of 8:

  in module Main
  at src/Main.purs:17:1 - 17:45 (line 17, column 1 - line 17, column 45)

    Module DOM.HTML.Types was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.

Error 7 of 8:

  in module Main
  at src/Main.purs:18:1 - 18:34 (line 18, column 1 - line 18, column 34)

    Module DOM.HTML.Window was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.

Error 8 of 8:

  in module Main
  at src/Main.purs:20:1 - 20:34 (line 20, column 1 - line 20, column 34)

    Module DOM.Node.Types was not found.
    Make sure the source file exists, and that it has been provided as an input to the compiler.


  See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,
  or to contribute content related to this error.


[error] Failed to build.
</code>

Well, the error messages kind of point you to the source of error - the modules have not been provided to the compiler.

Had to use documentation for each of the packages to match the types and fix the imports (since the example I have relied upon is way out of date):

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> spago</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> purescript-web-dom</span><span style="color:#40A02B;--shiki-dark:#A6D189"> purescript-web-html</span><span style="color:#40A02B;--shiki-dark:#A6D189"> react-dom</span></span></code>

And adjust the code itself:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">window</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML.HTMLDocument (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">body</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML.HTMLElement (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML.Window (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">document</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.DOM.Element (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Element</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReactDOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReactDOM</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM.Props </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Props</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Circle</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> |</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getShape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  writeState ctx { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getShape ((unsafeCoerce evt)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value) }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onCalculateAreaClicked ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readState ctx</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  writeState ctx { area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape value }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">areaCalculator</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React.ReactClass</span><span style="color:#179299;--shiki-dark:#81C8BE"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">areaCalculator </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">component </span><span style="color:#40A02B;--shiki-dark:#A6D189">"AreaCalculator"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> component</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  component ctx </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pure { state</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderFn ctx }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    renderFn ctx </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">readState ctx</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      return </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onChange (onShapeChanged ctx) ] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">              DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">              DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">              DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show value) ] []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onClick (onCalculateAreaClicked ctx) ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Calculate area"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Area: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show area))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> container </span><span style="color:#179299;--shiki-dark:#81C8BE">>>=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ReactDOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">render componentInstance</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  componentInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">createLeafElement areaCalculator {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  container</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> forall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> eff</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> (dom </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> eff) Element</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  container </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> do</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    win </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> window</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    doc </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> document win</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    elt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> body doc</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    return </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> toElement elt</span></span></code>

To get yet another error:

<code>Error found:
at src/Main.purs:22:21 - 22:22 (line 22, column 21 - line 22, column 22)

  Unable to parse module:
  Unexpected token '|'
</code>

That’s my bad, it is more Haskell than Elm or F#:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#D20F39;--shiki-dark:#E78284"> type Shape = Circle | Square</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> data Shape = Circle | Square</span></span></code>

And yet another one:

<code>Error found:
at src/Main.purs:45:3 - 45:8 (line 45, column 3 - line 45, column 8)

  Unable to parse module:
  Unexpected token 'where'
</code>

Because I did not indent my code enough.

And yet another one:

<code>Error found:
at src/Main.purs:47:32 - 47:34 (line 47, column 32 - line 47, column 34)

  Unable to parse module:
  Unexpected "&#x3C;-" in expression, perhaps due to a missing 'do' or 'ado' keyword
</code>

Because React.readState does not return effect, but rather the value itself, so no need to unpack it:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#D20F39;--shiki-dark:#E78284"> { shape, value, area } &#x3C;- React.readState ctx</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> let { shape, value, area } = React.readState ctx</span></span></code>

And yet another one:

<code>Error found:
at src/Main.purs:48:9 - 48:15 (line 48, column 9 - line 48, column 15)

  Unable to parse module:
  Unexpected token 'return'
</code>

Because I have forgot the do keyword:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#D20F39;--shiki-dark:#E78284"> renderFn ctx =</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> renderFn ctx = do</span></span></code>

Few small errors resolved:

<code>Compiling Main
Error 1 of 2:

  in module Main
  at src/Main.purs:26:33 - 26:38 (line 26, column 33 - line 26, column 38)

    Unknown type Float

# replace Float with Number, as Float is not really a type in PureScript

Error 2 of 2:

  in module Main
  at src/Main.purs:61:32 - 61:34 (line 61, column 32 - line 61, column 34)

    Unknown operator (++)
    
# replace ++ with + as ++ is not really an operator in PureScript
</code>

To end up with type errors hell:

<code>Error found:
in module Main
at src/Main.purs:60:13 - 60:54 (line 60, column 13 - line 60, column 54)

  Could not match type

    ReactElement

  with type

    Array t0 -> t1


while applying a function input [ value ((...) value)
                                ]
  of type ReactElement
  to argument []
while checking that expression (input [ value (...)
                                      ]
                               )
                               []
  has type ReactElement
in value declaration areaCalculator

where t0 is an unknown type
      t1 is an unknown type
</code>

What this tells you is that input function does not take a second argument (which would normally be similar to React.DOM.div [ attributes ] [ children ] ).

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#D20F39;--shiki-dark:#E78284"> DOM.input [ Props.value (show value) ] []</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DOM.input [ Props.value (show value) ]</span></span></code>

Earlier I have mentioned type hell. Well, that was just the small example. Here’s the next error in the code:

<code>Error found:
in module Main
at src/Main.purs:46:18 - 46:50 (line 46, column 18 - line 46, column 50)

  Could not match type

    Int

  with type

    Number


while trying to match type
                             ( area :: Int
                             , shape :: Maybe t3
                             , value :: Int
                             ...
                             )

  with type
              ( area :: Number
              , shape :: Maybe Shape
              , value :: Number
              ...
              | t1
              )

while solving type class constraint

  Prim.Row.Nub t0
               ( componentDidCatch :: Error
                                      -> { componentStack :: String
                                         }
                                         -> Effect Unit
               , componentDidMount :: Effect Unit
               , componentDidUpdate :: Record ()
                                       -> { area :: Number
                                          , shape :: ...
                                          , value :: Number
                                          | t1
                                          }
                                          -> t2 -> ...
               , componentWillUnmount :: Effect Unit
               , getSnapshotBeforeUpdate :: Record ()
                                            -> { area :: Number
                                               , shape :: ...
                                               , value :: Number
                                               | t1
                                               }
                                               -> Effect t2
               , render :: Effect ReactElement
               , shouldComponentUpdate :: Record ()
                                          -> { area :: Number
                                             , shape :: ...
                                             , value :: Number
                                             | t1
                                             }
                                             -> Effect Boolean
               , state :: { area :: Number
                          , shape :: Maybe Shape
                          , value :: Number
                          | t1
                          }
               , unsafeComponentWillMount :: Effect Unit
               , unsafeComponentWillReceiveProps :: Record () -> Effect Unit
               , unsafeComponentWillUpdate :: Record ()
                                              -> { area :: Number
                                                 , shape :: ...
                                                 , value :: Number
                                                 | t1
                                                 }
                                                 -> Effect Unit
               )

while inferring the type of component "AreaCalculator"
in value declaration areaCalculator

where t1 is an unknown type
      t3 is an unknown type
      t0 is an unknown type
      t2 is an unknown type

See https://github.com/purescript/documentation/blob/master/errors/TypesDoNotUnify.md for more information,
or to contribute content related to this error.
</code>

Basically compiler is trying to say the initial state provided has a type ( area :: Int, value :: Int, shape :: Maybe t3 ) but what is expected (down in the code) is ( area :: Number, value :: Number, shape :: Maybe Shape ) . Quite an explanation.

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> initialState :: AreaCalculatorState</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> initialState = { shape: Nothing, value: 0.0, area: 0.0 }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#D20F39;--shiki-dark:#E78284"> componentImpl ctx = pure { state: { shape: Nothing, value: 0.0, area: 0.0 }, render: renderFn ctx }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> componentImpl ctx = pure { state: initialState, render: renderFn ctx }</span></span></code>

And back to a new error:

<code>Error found:
in module Main
at src/Main.purs:70:23 - 70:45 (line 70, column 23 - line 70, column 45)

  No type class instance was found for

    Data.Semiring.Semiring String


while applying a function add
  of type Semiring t0 => t0 -> t0 -> t0
  to argument "Area: "
while inferring the type of add "Area: "
in value declaration areaCalculator

where t0 is an unknown type

See https://github.com/purescript/documentation/blob/master/errors/NoInstanceFound.md for more information,
or to contribute content related to this error.
</code>

Which means the + operator (function) does not apply to strings. The &#x3C;> is the string concatenation operator in this case. Although very hectic, it is described in the docs .

And yet another error:

<code>Error found:
in module Main
at src/Main.purs:78:21 - 78:29 (line 78, column 21 - line 78, column 29)

  Could not match type

    Effect

  with type

    Maybe


while trying to match type Effect (Maybe HTMLElement)
  with type Maybe t0
while checking that expression body doc
  has type Maybe t0
in value declaration main

where t0 is an unknown type

See https://github.com/purescript/documentation/blob/master/errors/TypesDoNotUnify.md for more information,
or to contribute content related to this error.
</code>

Which is all about matching the return types and handling them properly:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#D20F39;--shiki-dark:#E78284"> elt &#x3C;- toElement elt</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> let elt = fromJust eltMaybe</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> let container = toElement elt</span></span></code>

And finally, the version that compiles :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Effect (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Effect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">window</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML.HTMLDocument (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">body</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML.HTMLElement (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.HTML.Window (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">document</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Web.DOM.Element (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Element</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Unsafe.Coerce (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">unsafeCoerce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReactDOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ReactDOM</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React.DOM.Props </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Props</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">data</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Nothing</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pi </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">calculateArea (</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getShape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Circle</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Square</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getShape _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onShapeChanged ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">setState ctx { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getShape ((unsafeCoerce evt)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value) }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onCalculateAreaClicked ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getState ctx</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">setState ctx { area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape value }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> AreaCalculatorState</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#179299;--shiki-dark:#81C8BE"> {</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe Shape, value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number, area </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number </span><span style="color:#179299;--shiki-dark:#81C8BE">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">initialState</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> AreaCalculatorState</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">initialState </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { shape</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">areaCalculator</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React.ReactClass</span><span style="color:#179299;--shiki-dark:#81C8BE"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">areaCalculator </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">component </span><span style="color:#40A02B;--shiki-dark:#A6D189">"AreaCalculator"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> componentImpl</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  componentImpl ctx </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pure { state</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> initialState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> render</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderFn ctx }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    where</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      renderFn ctx' </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        { shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area } </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">getState ctx'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        pure </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">select [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onChange (onShapeChanged ctx') ] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Circle"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Square"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value (show value) ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">Props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onClick (onCalculateAreaClicked ctx') ] [ </span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Calculate area"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div [] [</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Area: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (show area))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> componentInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">createLeafElement areaCalculator {}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  win </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  doc </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document win</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  eltMaybe </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body doc</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromJust eltMaybe</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> container </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> toElement elt</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  ReactDOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">render componentInstance container</span></span></code>

Of course, there are few warnings and few sloppy solutions worth fixing:

<code>Warning 1 of 7:

  in module Main
  at src/Main.purs:7:1 - 7:18 (line 7, column 1 - line 7, column 18)

    Module Data.Maybe has unspecified imports, consider using the explicit form:

      import Data.Maybe (Maybe(..), fromJust)



  See https://github.com/purescript/documentation/blob/master/errors/ImplicitImport.md for more information,
  or to contribute content related to this warning.

Warning 2 of 7:

  in module Main
  at src/Main.purs:5:1 - 5:23 (line 5, column 1 - line 5, column 23)

    The import of Effect is redundant


  See https://github.com/purescript/documentation/blob/master/errors/UnusedImport.md for more information,
  or to contribute content related to this warning.

Warning 3 of 7:

  in module Main
  at src/Main.purs:3:1 - 3:15 (line 3, column 1 - line 3, column 15)

    Module Prelude has unspecified imports, consider using the explicit form:

      import Prelude (bind, pure, show, ($), (*), (&#x3C;>))



  See https://github.com/purescript/documentation/blob/master/errors/ImplicitImport.md for more information,
  or to contribute content related to this warning.

Warning 4 of 7:

  in module Main
  at src/Main.purs:16:1 - 16:35 (line 16, column 1 - line 16, column 35)

    The import of Web.DOM.Element is redundant


  See https://github.com/purescript/documentation/blob/master/errors/UnusedImport.md for more information,
  or to contribute content related to this warning.

Warning 5 of 7:

  in module Main
  at src/Main.purs:38:1 - 39:75 (line 38, column 1 - line 39, column 75)

    No type declaration was provided for the top-level declaration of onShapeChanged.
    It is good practice to provide type declarations as a form of documentation.
    The inferred type of onShapeChanged was:

      forall t10 t14 t8.
        ReactThis t10
          { shape :: ...
          | t8
          }
        -> t14 -> Effect Unit


  in value declaration onShapeChanged

  See https://github.com/purescript/documentation/blob/master/errors/MissingTypeDeclaration.md for more information,
  or to contribute content related to this warning.

Warning 6 of 7:

  in module Main
  at src/Main.purs:41:1 - 43:57 (line 41, column 1 - line 43, column 57)

    No type declaration was provided for the top-level declaration of onCalculateAreaClicked.
    It is good practice to provide type declarations as a form of documentation.
    The inferred type of onCalculateAreaClicked was:

      forall t24 t37 t39.
        ReactThis t37
          { area :: Number
          , shape :: ...
          , value :: Number
          | t39
          }
        -> t24 -> Effect Unit


  in value declaration onCalculateAreaClicked

  See https://github.com/purescript/documentation/blob/master/errors/MissingTypeDeclaration.md for more information,
  or to contribute content related to this warning.

Warning 7 of 7:

  in module Main
  at src/Main.purs:74:1 - 81:46 (line 74, column 1 - line 81, column 46)

    No type declaration was provided for the top-level declaration of main.
    It is good practice to provide type declarations as a form of documentation.
    The inferred type of main was:

      Partial => Effect (Maybe ReactComponent)


  in value declaration main

  See https://github.com/purescript/documentation/blob/master/errors/MissingTypeDeclaration.md for more information,
  or to contribute content related to this warning.
</code>

Essentially,

<code>Module Data.Maybe has unspecified imports, consider using the explicit form:

      import Data.Maybe (Maybe(..), fromJust)
</code>

is fixed with the suggested code:

<code>import Data.Maybe (Maybe(..), fromJust)
</code>

Same with the unnecessary imports.

This one looks neat:

<code>Warning 5 of 7:

  in module Main
  at src/Main.purs:38:1 - 39:75 (line 38, column 1 - line 39, column 75)

    No type declaration was provided for the top-level declaration of onShapeChanged.
    It is good practice to provide type declarations as a form of documentation.
    The inferred type of onShapeChanged was:

      forall t10 t14 t8.
        ReactThis t10
          { shape :: ...
          | t8
          }
        -> t14 -> Effect Unit


  in value declaration onShapeChanged

  See https://github.com/purescript/documentation/blob/master/errors/MissingTypeDeclaration.md for more information,
  or to contribute content related to this warning.
</code>

Compiler asks you to explicitly type the function declaration. But I don’t care about that for now.

In order to run the app, few actions are still needed:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> yarn</span><span style="color:#40A02B;--shiki-dark:#A6D189"> add</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -D</span><span style="color:#40A02B;--shiki-dark:#A6D189"> spago</span><span style="color:#40A02B;--shiki-dark:#A6D189"> purescript</span><span style="color:#40A02B;--shiki-dark:#A6D189"> parcel</span></span></code>

Then, one will need an entry point:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;!DOCTYPE</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> lang</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"en"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">meta</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> charset</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"UTF-8"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">meta</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> name</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"viewport"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> content</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"width=device-width, initial-scale=1.0"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">title</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Document</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">title</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> src</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"index.js"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x3C;</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

with a script:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'./output/Main'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Main</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

To build that whole thing now:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> yarn</span><span style="color:#40A02B;--shiki-dark:#A6D189"> spago</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x26;&#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> yarn</span><span style="color:#40A02B;--shiki-dark:#A6D189"> parcel</span><span style="color:#40A02B;--shiki-dark:#A6D189"> index.html</span></span></code>

And finally, if you run this, nothing will work.

All because the return type of the main function is not really Effect Unit , but rather a function. To fix this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mountMain</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> HTMLElement</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mountMain elt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> container </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> toElement elt</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> componentInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">createLeafElement areaCalculator {}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> componentMaybe </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> ReactDOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">render componentInstance container</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  void componentMaybe</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Effect</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Unit</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  win </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> window</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  doc </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document win</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  eltMaybe </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body doc</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  maybe (pure unit) mount eltMaybe</span></span></code>

And the thing still won’t completely work, since we do not modify the state on input value change:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Float.Parse (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parseFloat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">onValueChanged ctx evt </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newValue </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fromMaybe </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (parseFloat ((unsafeCoerce evt)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value))</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">  React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">setState ctx { value</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newValue }</span></span></code>

Final solution is available on sandbox .

Strongly-typed front-end: experiment 2, simple application, in ReasonML urn:uuid:22cee099-6624-51c9-a741-53807f6b1196 2021-04-19T00:00:00Z 2021-04-19T00:00:00Z

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

For the sake of experiment, I have decided to implement the very same application in ReasonML → ReScript by Facebook.

Starting the React Hooks example on Try ReasonML website, you get this code, which resembles some of the React features, just in a slightly weird syntax:

<code class="language-reason">[@bs.config {jsx: 3}];

module Counter = {
  [@react.component]
  let make = (~name) => {
    let (count, setCount) = React.useState(() => 0);

    &#x3C;div>
      &#x3C;p> {React.string(name ++ " clicked " ++ string_of_int(count) ++ " times")} &#x3C;/p>
      &#x3C;button onClick={_ => setCount(_ => count + 1)}>
        {React.string("Click me")}
      &#x3C;/button>
    &#x3C;/div>
  };
};

ReactDOMRe.renderToElementWithId(&#x3C;Counter name="Counter" />, "preview");
</code>

Starting off by defining the enum type for shape:

<code class="language-reason">type Shape = Circle | Square;
</code>

And immediately getting an error:

<code>Line 4:8-12 A type name must start with a lower-case letter or an underscore
</code>

That one is easy to fix:

<code class="language-reason">type shape = Circle | Square;
</code>

Now, add some markup:

<code class="language-reason">[@react.component]
let make = (~name) => {
  let (_shape, setShape) = React.useState(() => None);
  let (value, setValue) = React.useState(() => 0.0);
  let (area, setArea) = React.useState(() => 0.0);

  &#x3C;div>
    &#x3C;select>
      &#x3C;option value=""> Choose shape &#x3C;/option>
      &#x3C;option value="circle"> Circle &#x3C;/option>
      &#x3C;option value="square"> Square &#x3C;/option>
    &#x3C;/select>
    &#x3C;input value={value} />
    &#x3C;p> {React.string(string_of_float(area))} &#x3C;/p>
    &#x3C;button>
      {React.string("Calculate")}
    &#x3C;/button>
  &#x3C;/div>
};
</code>
Artem Shubovych

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

For the sake of experiment, I have decided to implement the very same application in ReasonML → ReScript by Facebook.

Starting the React Hooks example on Try ReasonML website, you get this code, which resembles some of the React features, just in a slightly weird syntax:

<code class="language-reason">[@bs.config {jsx: 3}];

module Counter = {
  [@react.component]
  let make = (~name) => {
    let (count, setCount) = React.useState(() => 0);

    &#x3C;div>
      &#x3C;p> {React.string(name ++ " clicked " ++ string_of_int(count) ++ " times")} &#x3C;/p>
      &#x3C;button onClick={_ => setCount(_ => count + 1)}>
        {React.string("Click me")}
      &#x3C;/button>
    &#x3C;/div>
  };
};

ReactDOMRe.renderToElementWithId(&#x3C;Counter name="Counter" />, "preview");
</code>

Starting off by defining the enum type for shape:

<code class="language-reason">type Shape = Circle | Square;
</code>

And immediately getting an error:

<code>Line 4:8-12 A type name must start with a lower-case letter or an underscore
</code>

That one is easy to fix:

<code class="language-reason">type shape = Circle | Square;
</code>

Now, add some markup:

<code class="language-reason">[@react.component]
let make = (~name) => {
  let (_shape, setShape) = React.useState(() => None);
  let (value, setValue) = React.useState(() => 0.0);
  let (area, setArea) = React.useState(() => 0.0);

  &#x3C;div>
    &#x3C;select>
      &#x3C;option value=""> Choose shape &#x3C;/option>
      &#x3C;option value="circle"> Circle &#x3C;/option>
      &#x3C;option value="square"> Square &#x3C;/option>
    &#x3C;/select>
    &#x3C;input value={value} />
    &#x3C;p> {React.string(string_of_float(area))} &#x3C;/p>
    &#x3C;button>
      {React.string("Calculate")}
    &#x3C;/button>
  &#x3C;/div>
};
</code>

And getting hit by another error:

<code>We've found a bug for you!
OCaml preview 14:52-57

The variant constructor Choose can't be found.

- If it's defined in another module or file, bring it into scope by:
  - Annotating it with said module name: let food = MyModule.Apple
  - Or specifying its type: let food: MyModule.fruit = Apple
- Constructors and modules are both capitalized. Did you want the latter?
  Then instead of let foo = Bar, try module Foo = Bar.
</code>

Not extremely helpful. Having to look into the OCaml code compiled from ReasonML:

<code class="language-reason">[@@@bs.config { jsx = 3 }]
module Counter =
  struct
    type shape =
      | Circle
      | Square
    let make ~name  =
      let (_shape,setShape) = React.useState (fun ()  -> None) in
      let (value,setValue) = React.useState (fun ()  -> 0.0) in
      let (area,setArea) = React.useState (fun ()  -> 0.0) in
      ((div
          ~children:[((select
                         ~children:[((option ~value:""
                                        ~children:[Choose; shape] ())
                                   [@JSX ]);
                                   ((option
                                       ~value:(("circle")[@reason.raw_literal
                                                           "circle"])
                                       ~children:[Circle] ())[@JSX ]);
                                   ((option
                                       ~value:(("square")[@reason.raw_literal
                                                           "square"])
                                       ~children:[Square] ())[@JSX ])] ())
                    [@JSX ]);
                    ((input ~value ~children:[] ())[@JSX ]);
                    ((p ~children:[React.string (string_of_float area)] ())
                    [@JSX ]);
                    ((button
                        ~children:[React.string
                                     (("Calculate")[@reason.raw_literal
                                                     "Calculate"])] ())
                    [@JSX ])] ())[@JSX ])[@@react.component ]
  end
let _ =
  ReactDOMRe.renderToElementWithId
    ((Counter.createElement
        ~name:(("Counter")[@reason.raw_literal "Counter"]) ~children:[] ())
    [@JSX ]) (("preview")[@reason.raw_literal "preview"])
</code>

Seems that this JSX does not work well with strings. Looking into the original example, one can deduct the format:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">option</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Choose shape"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">option</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

And having to replace this everywhere in the JSX:

<code class="language-reason">[@react.component]
let make = (~name) => {
  let (_shape, setShape) = React.useState(() => None);
  let (value, setValue) = React.useState(() => 0.0);
  let (area, setArea) = React.useState(() => 0.0);

  &#x3C;div>
    &#x3C;select>
      &#x3C;option value="">{React.string("Choose shape")}&#x3C;/option>
      &#x3C;option value="circle">{React.string("Circle")}&#x3C;/option>
      &#x3C;option value="square">{React.string("Square")}&#x3C;/option>
    &#x3C;/select>
    &#x3C;input value={value} />
    &#x3C;p> {"Area:" ++ React.string(string_of_float(area))} &#x3C;/p>
    &#x3C;button>
      {React.string("Calculate")}
    &#x3C;/button>
  &#x3C;/div>
};
</code>

And the next error is

<code>We've found a bug for you!
OCaml preview 33:30-34

This has type:
  float
But somewhere wanted:
  string

You can convert a float to a string with string_of_float.
</code>

Seems that value={value} does not work out of the box too, since the value variable has the type float and this version of React expects it to be string . Okay, let’s use that string_of_float function:

<code class="language-reason">&#x3C;input value={string_of_float(value)} />
</code>

Apparently it is also not good enough:

<code>Warning number 3
OCaml preview 33:37-51

deprecated: Pervasives.string_of_float
Please use Js.Float.toString instead, string_of_float generates unparseable floats
</code>

So it should be

<code class="language-reason">&#x3C;input value={Js.Float.toString(value)} />
</code>

Okay, only the unused state setters left. Let’s implement the shapeChanged and the calculateArea helpers first:

<code class="language-reason">let shapeChanged = (shapeStr: string): option(shape) =>
      switch shapeStr {
        | "circle" => Some(Circle)
        | "square" => Some(Square)
        | _ => None
      };

let calculateArea = (_shape: shape, value: float) =>
      switch _shape {
        | Circle => Js.Math.PI * value * value
        | Square => value * value
      };
</code>

The Js.Math.PI is not accessible, apparently:

<code>We've found a bug for you!
OCaml preview 20:23-32

The variant constructor Js.Math.PI can't be found.

- If it's defined in another module or file, bring it into scope by:
  - Annotating it with said module name: let food = MyModule.Apple
  - Or specifying its type: let food: MyModule.fruit = Apple
- Constructors and modules are both capitalized. Did you want the latter?
  Then instead of let foo = Bar, try module Foo = Bar.
</code>

According to the docs , it is Js.Math._PI . But even after fixing that, there is a mysterious error now:

<code>We've found a bug for you!
OCaml preview 20:23-33

This has type:
  float
But somewhere wanted:
  int

You can convert a float to a int with int_of_float.If this is a literal, you want a number without a trailing dot (e.g. 20).
</code>

The error happens on this OCaml line:

<code class="language-reason">| Circle  -> (Js.Math._PI * value) * value
</code>

Not helpful at all. The trick is that OCaml uses different operators for integer and floating-point math. This should do the trick:

<code class="language-reason">| Circle -> Js.Math._PI *. value *. value
</code>

Now, the last bit: connecting the component to the state:

<code class="language-reason">&#x3C;select onChange={ event => setShape(shapeChanged(event.target.value)) }>
</code>

As usual, an error:

<code>We've found a bug for you!
OCaml preview 26:62-67

The record field target can't be found.

If it's defined in another module or file, bring it into scope by:
- Annotating it with said module name: let baby = {MyModule.age: 3}
- Or specifying its type: let baby: MyModule.person = {age: 3}
</code>

Apparently, this JSX implementation has its own ways of accessing event’s props:

<code class="language-reason">ReactEvent.Form.target(event)##value
</code>

The issue is that this code is a valid BuckleScript, but not ReasonML. These intuitions described in docs won’t work:

<code class="language-reason">setShape(shapeChanged(ReactEvent.Form.target(event).value))
</code>

And here we go again:

<code>We've found a bug for you!
OCaml preview 27:75-79

The record field value can't be found.

If it's defined in another module or file, bring it into scope by:
- Annotating it with said module name: let baby = {MyModule.age: 3}
- Or specifying its type: let baby: MyModule.person = {age: 3}
setShape(shapeChanged(ReactEvent.Form.target(event)["value"]))

We've found a bug for you!
OCaml preview 27:45-74

This has type:
  &#x3C; .. > Js.t
But somewhere wanted:
  'a array
</code>

I am yet to figure out WTF is going on there, but the rough solution would be to just smash some JS code in:

<code class="language-reason">&#x3C;select onChange={ event => {
        let v: string = [%bs.raw {| event.target.value |}];
        let s: option(shape) = shapeChanged(v);
        setShape(s)
      }}>
</code>

That worked just enough to show yet another error:

<code>We've found a bug for you!
OCaml preview 28:48

This has type:
  shape option
But somewhere wanted:
  'a option -> 'a option
</code>

This is because state setters take a function, not just a value:

<code class="language-reason">setShape(_ => s)
</code>

And the whole event handler can be simplified a little bit:

<code class="language-reason">&#x3C;select onChange={ event => {
        let v: string = [%bs.raw {| event.target.value |}];
        setShape(_ => shapeChanged(v))
      }}>
</code>

This breaks some of the type checking benefits, but it just works ™️ ©

Back to the other event handlers:

<code class="language-reason">&#x3C;input value={Js.Float.toString(value)} onChange={ event => {
        let v: string = [%bs.raw {| event.target.value |}];
        setValue(_ => float_of_string(v));
      }} />
</code>

Surprisingly enough, here ReasonML is totally fine with float_of_string .

<code class="language-reason">&#x3C;button onClick={ _ => {
        setArea(_ => Belt.Option.mapWithDefault(_shape, 0.0, s => calculateArea(s, value)))
      }}>
</code>

Tricky Belt library way to work with option s.

Now that the code is done and seems to work in the playground, it is time to introduce yet another issue with raw technology by Facebook: it has actually four completely different and incompatible versions:

Each of them has incompatible syntax, all of them use the docs of one another (in particular, React docs are written for BuckleScript, but refer to ReScript docs).

Despite the bold proclamations like

// ReScript / old Reason syntax should parse just // fine (go to the "Settings" panel for toggling syntax).

And

What Will Change with ReScript?

Technically, not much. One of our main goals is to keep backwards compatibility for existing BuckleScript codebases and will provide an automated upgrade path from .re (Reason) to .res (ReScript) files.

The BuckleScript compiler toolchain and its new .res syntax will be unified into one platform called ReScript. Upgrading from the bs-platform to the soon-to-be-published ReScript npm package will just be a matter of updating your package.json file. Syntax wise, we believe that previous Reason users will feel right at home.

ReScript will continue shipping the old Reason v3.6 syntax as well and it will be possible to mix .re and .res files in one codebase (same with libraries).

If you try to run the ReasonML code that works in ReasonML playground in ReScript playground, you will notice that it does not even compile:

<code>[E] Line 6, column 19:
Missing expression
[E] Line 12, column 49:
Type parameters require angle brackets:
  option&#x3C;shape>
[E] Line 27, column 32:
Did you forget a `,` here? 
[E] Line 27, column 57:
Did you forget a `}` here? 
[E] Line 36, column 32:
Did you forget a `,` here? 
</code>

With a few changes following intuition (and not those useless error messages), one can get it to compile:

<code class="language-reason">// no more [%bs] annotations
module Counter = {
  type shape = Circle | Square;
  
  @react.component // annotations look more java-like or typescript-like
  let make = () => {
    let (_shape, setShape) = React.useState(() => None);
    let (value, setValue) = React.useState(() => 0.0);
    let (area, setArea) = React.useState(() => 0.0);
    
    // option(type) is now option&#x3C;type>
    let shapeChanged = (shapeStr: string): option&#x3C;shape> =>
      switch shapeStr {
        | "circle" => Some(Circle)
        | "square" => Some(Square)
        | _ => None
      };
    
    let calculateArea = (_shape: shape, value: float) =>
      switch _shape {
        | Circle => Js.Math._PI *. value *. value
        | Square => value *. value
      };

    &#x3C;div>
      &#x3C;select onChange={ event => {
        // the issue with event.target.value is somewhat resolved
        let v: string = ReactEvent.Form.target(event)["value"];
        setShape(_ => shapeChanged(v))
      }}>
        &#x3C;option value="">{React.string("Choose shape")}&#x3C;/option>
        &#x3C;option value="circle">{React.string("Circle")}&#x3C;/option>
        &#x3C;option value="square">{React.string("Square")}&#x3C;/option>
      &#x3C;/select>
      
      &#x3C;input value={Js.Float.toString(value)} onChange={ event => {
        let v: string = ReactEvent.Form.target(event)["value"];
        setValue(_ => float_of_string(v));
      }} />
      
      &#x3C;p>{React.string("Area:" ++ Js.Float.toString(area))}&#x3C;/p>

      &#x3C;button onClick={ _ => {
        setArea(_ => Belt.Option.mapWithDefault(_shape, 0.0, s => calculateArea(s, value)))
      }}>
        {React.string("Calculate")}
      &#x3C;/button>
    &#x3C;/div>
  };
};
</code>

TL;DR:

One can't simply...
Strongly-typed front-end: experiment 2, simple application, in F# urn:uuid:f1123f57-cfa2-5cf7-aafa-7a28f8b93593 2021-04-19T00:00:00Z 2021-04-19T00:00:00Z

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

In F# world, there is a framework called Fable . It allows one to compile their F# code to JavaScript. There is a built-in package for React, but Fable developers themselves suggest using Elmish , which is a framework similar to Elm, just suited for F#.

A sample Elmish application in the online editor looks like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish.SimpleInput</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">(**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">Minimal application showing how to use Elmish</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">You can find more info about Emish architecture and samples at https://elmish.github.io/</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">*)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">JsInterop</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Props</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// MODEL</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ChangeValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> init</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// UPDATE</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ChangeValue newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// VIEW (rendered with React)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> model dispatch </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    div </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Class </span><span style="color:#40A02B;--shiki-dark:#A6D189">"main-container"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Class </span><span style="color:#40A02B;--shiki-dark:#A6D189">"input"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  Value model.Value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  OnChange </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ev </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ev.target?value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ChangeValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          span </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Hello, "</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              str model.Value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"!"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// App</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Program.mkProgram init update view</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withConsoleTrace</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withReactSynchronous </span><span style="color:#40A02B;--shiki-dark:#A6D189">"elmish-app"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.run</span></span></code>

One can easily see the similarities to Elm (or so I think).

Artem Shubovych

Contents

  1. Introduction
  2. Experiment 1, hex2rgb
  3. Experiment 2, simple application

In F# world, there is a framework called Fable . It allows one to compile their F# code to JavaScript. There is a built-in package for React, but Fable developers themselves suggest using Elmish , which is a framework similar to Elm, just suited for F#.

A sample Elmish application in the online editor looks like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish.SimpleInput</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">(**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">Minimal application showing how to use Elmish</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">You can find more info about Emish architecture and samples at https://elmish.github.io/</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">*)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">JsInterop</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Props</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// MODEL</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ChangeValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> init</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// UPDATE</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ChangeValue newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// VIEW (rendered with React)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> model dispatch </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    div </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Class </span><span style="color:#40A02B;--shiki-dark:#A6D189">"main-container"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Class </span><span style="color:#40A02B;--shiki-dark:#A6D189">"input"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  Value model.Value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  OnChange </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> ev </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ev.target?value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ChangeValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          span </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Hello, "</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              str model.Value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"!"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// App</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Program.mkProgram init update view</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withConsoleTrace</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withReactSynchronous </span><span style="color:#40A02B;--shiki-dark:#A6D189">"elmish-app"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.run</span></span></code>

One can easily see the similarities to Elm (or so I think).

Rewriting it to the application from above should not be a problem, right?

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish.SimpleInput</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">(**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">Minimal application showing how to use Elmish</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">You can find more info about Emish architecture and samples at https://elmish.github.io/</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">*)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">JsInterop</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Props</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// MODEL</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Rectangle </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Circle</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Circle </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math.PI</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Rectangle </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Option</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">>;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> float </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ValueChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> float</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CalculateArea</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> init</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Option.None</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// UPDATE</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ValueChanged newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged newShape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newShape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CalculateArea </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea model.shape model.value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// VIEW (rendered with React)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> model dispatch </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    div </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> select </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OnChange </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> evt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> evt.target?value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            option </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            option </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            option </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"rectangle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">          ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          input </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value model.Value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  OnChange </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> evt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> evt.target?value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> float </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ValueChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          button </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OnClick </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> evt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch CalculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Calculate area"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          span </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Area: "</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              str model.Area</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// App</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Program.mkProgram init update view</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withConsoleTrace</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withReactSynchronous </span><span style="color:#40A02B;--shiki-dark:#A6D189">"elmish-app"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.run</span></span></code>

I deliberately skipped few things to check what errors will I get from the compiler.

Now to the errors:

<code>    | Circle -> value * value * Math.PI
The value, constructor, namespace or type 'PI' is not defined.
| ShapeChanged newShape ->
        { model with shape = newShape }, Cmd.none
This expression was expected to have type
    'Shape'    
but here has type
    'Shape option'
| CalculateArea ->
        { model with area = calculateArea model.shape model.value }
All branches of a pattern match expression must return values of the same type as the first branch, which here is 'Model * Cmd&#x3C;'a>'. This branch returns a value of type 'Model'.
[ select [ OnChange (fun evt -> evt.target.value |> string |> ShapeChanged |> dispatch) ] [
            option [ Value "circle" ]
            option [ Value "rectangle" ]
          ]
          
The type 'EventTarget' does not define the field, constructor or member 'value'.

Type mismatch. Expecting a
    'string -> 'a'    
but given a
    'Shape -> Msg'    
The type 'string' does not match the type 'Shape'

The type ''a -> ReactElement' is not compatible with the type 'ReactElement' (x2)
span [ ]
            [ str "Area: "
              str model.Area
            ]
            
Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
</code>

The errors might be a tiny bit mysterious at times, but using simple intuition one can easily fix them all.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish.SimpleInput</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">JsInterop</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Fable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Props</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elmish</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">React</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// MODEL</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Rectangle </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Circle</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Circle </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math.PI</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Rectangle </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getShape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">):</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Option</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "circle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Option.Some Circle</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "rectangle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Option.Some Rectangle</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> _</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Option.None</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Option</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Shape</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">>;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> float </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ValueChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CalculateArea</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> init</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Option.None</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// UPDATE</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Msg</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Model</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ValueChanged newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> float newValue </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged newShape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> getShape newShape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CalculateArea </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newArea </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> </span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Option.map </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> shape </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> calculateArea shape model.value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model.shape</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Option.defaultValue </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> area </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> newArea </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Cmd.none</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// VIEW</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> model dispatch </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    div </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> select </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OnChange </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> evt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> evt.target?value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ShapeChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            option </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Select shape"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            option </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"circle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Circle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            option </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#40A02B;--shiki-dark:#A6D189">"rectangle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Rectangle"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">          ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          input </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value model.value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  OnChange </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> evt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> evt.target?value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ValueChanged </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          button </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OnClick </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> evt </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch CalculateArea</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Calculate area"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          span </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Area: "</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">              str </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string model.area</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            ]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// App</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Program.mkProgram init update view</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withConsoleTrace</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.withReactSynchronous </span><span style="color:#40A02B;--shiki-dark:#A6D189">"elmish-app"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">|></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Program.run</span></span></code>

TL;DR:

Not bad
Experiment #1: mismatching type handling & error helpfulness urn:uuid:2adee697-949e-5976-bd6e-c7f49f5a7989 2021-04-19T00:00:00Z 2021-04-19T00:00:00Z

Contents

  1. Introduction
  2. Experiment 1, hex2rgb (you are here)
  3. Experiment 2, simple application

For a sake 🍶of science experiment, I have converted one function of a library I created long time ago to multiple languages that compile to JS and called it with various values.

The function is simple - it takes a color represented as a HEX string and converts it to { r, g, b } object.

The test is relatively big - it passes various numbers (integer and floating point, negative and positive), booleans, objects, arrays, obvious candidates - null and undefined and incorrect string.

The implementations are made with:

  • Scala.js
  • ReasonML
  • F#
  • PureScript
  • TypeScript
  • Elm

Implementations

Scala.JS

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> darken_color</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scala</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scalajs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">js</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scala</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scalajs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">js</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">annotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> js.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">@</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JSExportTopLevel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"DarkenColor"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">object</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DarkenColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  @</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JSExport</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">s</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> """^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.r</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgbStr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re(rStr, gStr, bStr) </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((rStr, gStr, bStr))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> None</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    rgbStr.map (x </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Integer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.parseInt(x._1, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Integer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.parseInt(x._2, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Integer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.parseInt(x._3, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))).getOrElse(</span><span style="color:#D20F39;--shiki-dark:#E78284">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

ReasonML

<code class="language-reason">type rgb = {
  r: int,
  g: int,
  b: int,
}

let parse_hex = s => int_of_string("0x" ++ s)

let hex2rgb = hex =>
  Js.Re.fromString("^#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$")
    -> Js.Re.exec_(hex)
    -> Belt.Option.map (Js.Re.captures)
    -> Belt.Option.map (Js.Array.map (Js.Nullable.toOption))
    -> Belt.Option.map (x => Js.Array.sliceFrom(1, x))
    -> Belt.Option.map (Js.Array.map (x => Belt.Option.map(x, parse_hex)))
    -> (matches => switch matches {
      | Some([ Some(r), Some(g), Some(b) ]) => Some({ r: r, g: g, b: b })
      | _ => None
    })
</code>

PureScript

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> map</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ($)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> (&#x3C;#>)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> (>>=)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> (>>>)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Array (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catMaybes</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Array.NonEmpty (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Int (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromStringAs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hexadecimal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Nullable (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Nullable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toNullable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Either (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hush</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.String.Regex (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">regex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.String.Regex.Flags (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ignoreCase</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int,</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    g </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int,</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">constructRGB</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">constructRGB [ r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b ] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">constructRGB _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Nullable</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex2rgb hexString </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  toNullable </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ((hush </span><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> join) </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (regex </span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ignoreCase) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">re </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (match re hexString)))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> catMaybes</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (map (fromStringAs hexadecimal))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> catMaybes</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  >>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> constructRGB</span></span></code>

F#

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">RegularExpressions</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGBType</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> int16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> int16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> int16 </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hex2rgb</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">hex</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Regex.Match</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "^#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m.Success </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">then</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        m.Groups</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.cast</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Group</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.skip </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // zero capture group is always the full string, when it matches</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.map </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m.Value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.map </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System.Convert.ToInt16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.toList</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (function</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> []</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Some </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> _</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> None</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> None</span></span></code>

TypeScript

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGBType</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * Converts a HEX color value to RGB by extracting R, G and B values from string using regex.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * Returns r, g, and b values in range [0, 255]. Does not support RGBA colors just yet.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * </span><span style="color:#7C7F93;--shiki-dark:#949CBB">@</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">param</span><span style="color:#E64553;--shiki-dark:#EA999C"> hex</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> The color value</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * </span><span style="color:#7C7F93;--shiki-dark:#949CBB">@</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">returns</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> The RGB representation or {</span><span style="color:#7C7F93;--shiki-dark:#949CBB">@</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">code</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> null} if the string value is invalid</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">hex</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGBType</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shorthandRegex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> /</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#40A02B;--shiki-dark:#A6D189">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#40A02B;--shiki-dark:#A6D189">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  hex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hex</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">replace</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(shorthandRegex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_match</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> /</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#40A02B;--shiki-dark:#A6D189">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#179299;--shiki-dark:#81C8BE">{2}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#179299;--shiki-dark:#81C8BE">{2}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#179299;--shiki-dark:#81C8BE">{2}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">i</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exec</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(hex)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseInt</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseInt</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseInt</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hex2rgb </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Elm

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DarkenColor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">..</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">List</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.Extra</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Regex</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type alias </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">RGBType</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = { r: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, g: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, b: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex2rgb : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> RGBType</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex2rgb hex =</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    Regex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.from</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> "^#?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-9]{2}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-9]{2}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-9]{2}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">regex</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Regex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> regex</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">List</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">List</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toInt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.and</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Then</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Extra</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">combine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.and</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> construct</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">RGB</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">construct</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> list =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    case list of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ r, g, b ] -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { r = r, g = g, b = b }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _ -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.Nothing</span></span></code>

For fair comparison, the implementation is kept same (no platform-specific code, except Option in functional languages) and every single bundle is processed with Webpack 4.

The test checks both the result and the assumes no exception is thrown, even when the input is incorrect. For the interest sake, the exceptions thrown as well as bundle sizes will be listed below.

Gleam

A naive implementation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">list</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option.{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">regexp.{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">g: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">b: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> assert</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(re) </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> from_string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> assert</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">submatches: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str)]),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> scan</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">with: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">re, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">color)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> assert</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b)] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r, g, b)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

This produces approximately 8 KB bundle, but this implementation treats any error as a panic.

An implementation which handles the errors properly looks somewhat like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try_recover</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from_string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) { </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not parse regexp pattern"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgb_strs </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scan</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(re, color) {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">submatches: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str)])] </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">      Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([r_str, g_str, b_str])</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not match components of a regexp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  })</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse_res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">all</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(list.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(rgb_strs, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x) { int.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) }))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try_recover</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(parse_res, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) { </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not parse hex numbers"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) }),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgb {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [r, g, b] </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r, g, b))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not find three integer color components"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

Unfortunately, this one is a bit larger at 10 KB .

An idiomatic Gleam implementation would make use of separate helper functions:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parse_color</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map_error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from_string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) { </span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not parse regexp pattern"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scan</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(re, color) {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">submatches: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str)])] </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">      Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(#(r_str, g_str, b_str))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not match components of a regexp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">input: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map_error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(int.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">), </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "can not parse "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " as hexadecimal number"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  })</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #(r_str, g_str, b_str) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_color</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(color))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r, g, b))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

This implementation is the smallest of the bunch at 8.7 KB and as an added bonus, passes all the tests (unlike the previous implementations - in Gleam, that is).

Artem Shubovych

Contents

  1. Introduction
  2. Experiment 1, hex2rgb (you are here)
  3. Experiment 2, simple application

For a sake 🍶of science experiment, I have converted one function of a library I created long time ago to multiple languages that compile to JS and called it with various values.

The function is simple - it takes a color represented as a HEX string and converts it to { r, g, b } object.

The test is relatively big - it passes various numbers (integer and floating point, negative and positive), booleans, objects, arrays, obvious candidates - null and undefined and incorrect string.

The implementations are made with:

  • Scala.js
  • ReasonML
  • F#
  • PureScript
  • TypeScript
  • Elm

Implementations

Scala.JS

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> darken_color</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scala</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scalajs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">js</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scala</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scalajs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">js</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">annotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> js.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Object</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">@</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JSExportTopLevel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"DarkenColor"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">object</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DarkenColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  @</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">JSExport</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">s</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> """^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"""</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.r</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    val</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgbStr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> s </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re(rStr, gStr, bStr) </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((rStr, gStr, bStr))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> None</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    rgbStr.map (x </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Integer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.parseInt(x._1, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Integer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.parseInt(x._2, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Integer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.parseInt(x._3, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))).getOrElse(</span><span style="color:#D20F39;--shiki-dark:#E78284">null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

ReasonML

<code class="language-reason">type rgb = {
  r: int,
  g: int,
  b: int,
}

let parse_hex = s => int_of_string("0x" ++ s)

let hex2rgb = hex =>
  Js.Re.fromString("^#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$")
    -> Js.Re.exec_(hex)
    -> Belt.Option.map (Js.Re.captures)
    -> Belt.Option.map (Js.Array.map (Js.Nullable.toOption))
    -> Belt.Option.map (x => Js.Array.sliceFrom(1, x))
    -> Belt.Option.map (Js.Array.map (x => Belt.Option.map(x, parse_hex)))
    -> (matches => switch matches {
      | Some([ Some(r), Some(g), Some(b) ]) => Some({ r: r, g: g, b: b })
      | _ => None
    })
</code>

PureScript

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">where</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Prelude (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> map</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ($)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> (&#x3C;#>)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> (>>=)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> (>>>)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Array (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">catMaybes</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Array.NonEmpty (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Int (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromStringAs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hexadecimal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Maybe (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Maybe</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">(..)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Nullable (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Nullable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toNullable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.Either (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hush</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.String.Regex (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">regex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Data.String.Regex.Flags (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ignoreCase</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int,</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    g </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int,</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">constructRGB</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Array</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Maybe</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">constructRGB [ r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b ] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">constructRGB _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> Nothing</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> String</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Nullable</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex2rgb hexString </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  toNullable </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ((hush </span><span style="color:#179299;--shiki-dark:#81C8BE">>>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> join) </span><span style="color:#179299;--shiki-dark:#81C8BE">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (regex </span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ignoreCase) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">re </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (match re hexString)))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (drop </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> catMaybes</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (map (fromStringAs hexadecimal))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;#></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> catMaybes</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  >>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> constructRGB</span></span></code>

F#

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">open</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">RegularExpressions</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGBType</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> int16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> int16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> int16 </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hex2rgb</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">hex</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> string</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Regex.Match</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "^#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m.Success </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">then</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        m.Groups</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.cast</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Group</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.skip </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // zero capture group is always the full string, when it matches</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.map </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> m </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> m.Value</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.map </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(fun</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System.Convert.ToInt16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Seq.toList</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        |></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> (function</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> []</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Some </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> _</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> None</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> None</span></span></code>

TypeScript

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGBType</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> number</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * Converts a HEX color value to RGB by extracting R, G and B values from string using regex.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * Returns r, g, and b values in range [0, 255]. Does not support RGBA colors just yet.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * </span><span style="color:#7C7F93;--shiki-dark:#949CBB">@</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">param</span><span style="color:#E64553;--shiki-dark:#EA999C"> hex</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> The color value</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  * </span><span style="color:#7C7F93;--shiki-dark:#949CBB">@</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">returns</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> The RGB representation or {</span><span style="color:#7C7F93;--shiki-dark:#949CBB">@</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">code</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> null} if the string value is invalid</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">hex</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGBType</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shorthandRegex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> /</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#40A02B;--shiki-dark:#A6D189">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#40A02B;--shiki-dark:#A6D189">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  hex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hex</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">replace</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(shorthandRegex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_match</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> g</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> /</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#40A02B;--shiki-dark:#A6D189">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#179299;--shiki-dark:#81C8BE">{2}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#179299;--shiki-dark:#81C8BE">{2}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">[</span><span style="color:#DC8A78;--shiki-dark:#F2D5CF">a-f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\d</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">]</span><span style="color:#179299;--shiki-dark:#81C8BE">{2}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">i</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exec</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(hex)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseInt</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseInt</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseInt</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hex2rgb </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Elm

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DarkenColor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">..</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">List</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.Extra</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">import </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Regex</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type alias </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">RGBType</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = { r: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, g: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, b: </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex2rgb : </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> RGBType</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hex2rgb hex =</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    Regex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.from</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> "^#?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-9]{2}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-9]{2}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-9]{2}</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">\</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">regex</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Regex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> regex</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">List</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.map </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">List</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toInt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.and</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Then</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Extra</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">combine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        |> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.and</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> construct</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">RGB</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">construct</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> list =</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    case list of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [ r, g, b ] -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.Just</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> { r = r, g = g, b = b }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        _ -> </span><span style="color:#DF8E1D;--shiki-dark:#E5C890">Maybe.Nothing</span></span></code>

For fair comparison, the implementation is kept same (no platform-specific code, except Option in functional languages) and every single bundle is processed with Webpack 4.

The test checks both the result and the assumes no exception is thrown, even when the input is incorrect. For the interest sake, the exceptions thrown as well as bundle sizes will be listed below.

Gleam

A naive implementation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">list</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">option.{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">regexp.{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gleam</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> type</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">r: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">g: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">b: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> assert</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(re) </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> from_string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> assert</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">submatches: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str)]),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> scan</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">with: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">re, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">color)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> assert</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b)] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r, g, b)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

This produces approximately 8 KB bundle, but this implementation treats any error as a panic.

An implementation which handles the errors properly looks somewhat like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try_recover</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from_string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) { </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not parse regexp pattern"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgb_strs </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scan</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(re, color) {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">submatches: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str)])] </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">      Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([r_str, g_str, b_str])</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not match components of a regexp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  })</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> parse_res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">all</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(list.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(rgb_strs, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x) { int.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) }))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgb </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try_recover</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(parse_res, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) { </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not parse hex numbers"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) }),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rgb {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [r, g, b] </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r, g, b))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not find three integer color components"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

Unfortunately, this one is a bit larger at 10 KB .

An idiomatic Gleam implementation would make use of separate helper functions:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parse_color</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> re </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map_error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from_string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">),</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) { </span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not parse regexp pattern"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> regexp.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scan</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(re, color) {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Match</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">content: </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">submatches: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str), </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str)])] </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">      Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(#(r_str, g_str, b_str))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    _</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"can not match components of a regexp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">input: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map_error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(int.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">base_parse</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">), </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">_</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "can not parse "</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#40A02B;--shiki-dark:#A6D189"> " as hexadecimal number"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  })</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">pub</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fn</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">color: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #(r_str, g_str, b_str) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_color</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(color))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r_str))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(g_str))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  use</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">parse_hex</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(b_str))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  Ok</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">RGB</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(r, g, b))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span></span></code>

This implementation is the smallest of the bunch at 8.7 KB and as an added bonus, passes all the tests (unlike the previous implementations - in Gleam, that is).

The test

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FSharp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'./dist/bundle.fsharp.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Purescript </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'./dist/bundle.purescript.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Rescript </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'./dist/bundle.rescript.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ScalaJS </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'./dist/bundle.scalajs.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Typescript </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'./dist/bundle.typescript.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Gleam </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'./dist/bundle.gleam.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'DarkenColor'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> interpretations </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'F#'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FSharp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'PureScript'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Purescript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'ReScript'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Rescript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'ScalaJS'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ScalaJS</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">DarkenColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'TypeScript'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Typescript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    'Gleam'</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Gleam</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">entries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(interpretations)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">language</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> DarkenColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">`in </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">language</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'hex2rgb'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for valid input'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'with hash prefix'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'long HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#bede12'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'returns correct result'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMatchObject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 190</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 222</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            xdescribe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'short HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#bd7'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'returns correct result'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMatchObject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 187</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 221</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 119</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'no hash prefix'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'long HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'bede12'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'returns correct result'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMatchObject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 190</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 222</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 18</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            xdescribe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'short HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'bd7'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'returns correct result'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMatchObject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 187</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 221</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 119</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for invalid input'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid HEX string'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid number of digits'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'too few'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for long HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#bede1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                  it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                xdescribe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for short HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#be'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                  it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'too many'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for long HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#bede128'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                  it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                xdescribe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for short HEX'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#bede'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                  it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid letters'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#bfghij'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid characters'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#be!?12'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'spaces'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#be de  12'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'invalid prefix'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '?bede12'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for number'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'positive'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'floating point'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'integer'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 314</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'negative'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'floating point'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'integer'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">              const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">314</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">              }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'for object'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'null'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'undefined'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> undefined</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'NaN'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> NaN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'JSON'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> r</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 76</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 120</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'array'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#FE640B;--shiki-dark:#EF9F76">25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 76</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 120</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Boolean'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">          describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Map'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'does not fail'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">              expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DarkenColor</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hex2rgb</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(input))</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">not</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toThrow</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">          }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Test results

Here is a comparison of the test results:

Tool Test results
F#
PureScript
ReScript
ScalaJS
TypeScript
Elm n/a
Gleam

Error helpfulness

Some implementations still throw error when the data type is not what the function expects.

PureScript

<code>  ● DarkenColor › in PureScript › hex2rgb › for number › positive › integer › does not fail

    expect(received).not.toThrow()

    Error name:    "TypeError"
    Error message: "u.match is not a function"
    
  ● DarkenColor › in PureScript › hex2rgb › for object › null › does not fail

    expect(received).not.toThrow()

    Error name:    "TypeError"
    Error message: "Cannot read property 'match' of null"
    
  ● DarkenColor › in PureScript › hex2rgb › for object › undefined › does not fail

    expect(received).not.toThrow()

    Error name:    "TypeError"
    Error message: "Cannot read property 'match' of undefined"
</code>

ScalaJS

<code> ● DarkenColor › in ScalaJS › hex2rgb › for object › undefined › does not fail

    expect(received).not.toThrow()

    Error name:    "org.scalajs.linker.runtime.UndefinedBehaviorError"
    Error message: "java.lang.ClassCastException: undefined is not an instance of java.lang.String"

  ● DarkenColor › in ScalaJS › hex2rgb › for number › positive › floating point › does not fail

    expect(received).not.toThrow()

    Error name:    "org.scalajs.linker.runtime.UndefinedBehaviorError"
    Error message: "java.lang.ClassCastException: 3.14 is not an instance of java.lang.String"
</code>

TypeScript

<code> ● DarkenColor › in TypeScript › hex2rgb › for number › positive › floating point › does not fail

    expect(received).not.toThrow()

    Error name:    "TypeError"
    Error message: "e.replace is not a function"

  ● DarkenColor › in TypeScript › hex2rgb › for object › null › does not fail

    expect(received).not.toThrow()

    Error name:    "TypeError"
    Error message: "Cannot read property 'replace' of null"

  ● DarkenColor › in TypeScript › hex2rgb › for object › undefined › does not fail

    expect(received).not.toThrow()

    Error name:    "TypeError"
    Error message: "Cannot read property 'replace' of undefined"
</code>

Elm

<code>Detected problems in 1 module.
-- TYPE MISMATCH ------------------------------------------- src/DarkenColor.elm

The 1st argument to `hex2rgb` is not what I expect:

24| main = hex2rgb -12
                   ^^^
This argument is a number of type:

    number

But `hex2rgb` needs the 1st argument to be:

    String

Hint: Try using String.fromInt to convert it to a string?
</code>

Gleam

The implementation using a regular expression panics with not really helpful error messages:

<code> ● DarkenColor › in Gleam › hex2rgb › for number › positive › floating point › does not fail

    expect(received).not.toThrow()

    Error name:    "TypeError"
    Error message: "string.matchAll is not a function"
</code>

The pattern-matching-based implementation does not fail at all.

Bundle size

Tool Bundle size
F# 40K
PureScript 174K
ReScript 22K
ScalaJS 197K
TypeScript 1.4K
Elm n/a
Gleam 10.8K
Bundle size comparison
Rogue bomber urn:uuid:5157bee5-f3a8-5e0a-be43-4ad0996ba893 2021-03-25T00:00:00Z 2021-03-25T00:00:00Z Rogue bomber Artem Shubovych

This is a yet another show-off blog.

Yet another one-day-build, made specifically for not-so-exciting ShipIt-51 hackathon we are having at work right now.

This is a terrible code written in JS in matter of some 8 hrs.

Click the button below to start playing.

Gantt chart. Part 3 urn:uuid:90e533f3-3dcc-53e8-b248-b115694c293f 2021-03-04T00:00:00Z 2021-03-04T00:00:00Z

Contents

I have been writing about and improving on my Gantt chart implementation for quite some time now.

It all started with this ( blog ):

First revision of Gantt chart

Then I added few features ( blog ):

Second revision of Gantt chart

Back then I have promised to re-write the implementation in Canvas. And so I did.

Curious fact: I did not plan on doing this at this time - it was a private email from darekeapp12 who wrote this:

I have looked at your blog for Gantt chart and implementation. I am doing a project using React and Node/Express and need to implement Gantt chart that is also draggable i.e. the bars can be moved and also resized from either end. I have researched heavily but could not find anything. I am thinking if there is no library, something could be built from scratch.

The sender seemed dodgy ( DAREKE app ) so I did not want to reply to avoid unnecessary spam subscriptions, but I was happy to improve my old project.

Here are few new features and improvements added to the chart:

  • scrolling and zooming in & out is now a thing
  • you can drag the milestones around and stretch & shrink them
  • an event will be fired whenever a milestone is changed (moved / stretched / shrinked)
  • dependencies are now typed: start-to-start, end-to-end or end-to-start are the only supported types

Here, you can even play around with it now!

More about the implementation specifics under the cut.

Artem Shubovych

Contents

I have been writing about and improving on my Gantt chart implementation for quite some time now.

It all started with this ( blog ):

First revision of Gantt chart

Then I added few features ( blog ):

Second revision of Gantt chart

Back then I have promised to re-write the implementation in Canvas. And so I did.

Curious fact: I did not plan on doing this at this time - it was a private email from darekeapp12 who wrote this:

I have looked at your blog for Gantt chart and implementation. I am doing a project using React and Node/Express and need to implement Gantt chart that is also draggable i.e. the bars can be moved and also resized from either end. I have researched heavily but could not find anything. I am thinking if there is no library, something could be built from scratch.

The sender seemed dodgy ( DAREKE app ) so I did not want to reply to avoid unnecessary spam subscriptions, but I was happy to improve my old project.

Here are few new features and improvements added to the chart:

  • scrolling and zooming in & out is now a thing
  • you can drag the milestones around and stretch & shrink them
  • an event will be fired whenever a milestone is changed (moved / stretched / shrinked)
  • dependencies are now typed: start-to-start, end-to-end or end-to-start are the only supported types

Here, you can even play around with it now!

More about the implementation specifics under the cut.

The main goal I had in mind was getting rid of D3, since it is a rather heavy dependency which is only used for few rather simple functions. By the end of this rework I ended up adding a ton of visual and functional improvements to the implementation, but I'll talk about it in detail later.

To start with, I created a function to convert a timestamp into a position on canvas. This requires knowing the boundaries of timeline and canvas to be able to map the beginning of a timeline to a beginning of canvas. I started off by trying to figure out the formulae myself, but quickly realized it is not as simple as few additions and divisions (well, it actually is, but it is tricky to figure out from start). So I turned myself to the maths - linear interpolation, to be specific.

If we know the beginning of a range and the end of a range and values they map to, in order to figure out the corresponding mapping of a point on that range, we can utilize linear interpolation (given the range values changes linearly, which is true, since we work with time span on one hand and canvas coordinates on the other).

Here's a visual representation of what I am talking about:

Interpolation explained

There's a formulae to tell the y coordinate of a point on a line by its x coordinate if you know two points on that line.

Now in our case, the two known points are the start and the end of the time span. "But wait, why are we even taling about x and y coordinates?" - you might ask. A given timestamp can be represented as a single number (number of milliseconds since Unix was started). That would give us the x coordinate of any given point. The y coordinate would be the x coordinate of the same point on canvas. We do not care about the y coordinate on canvas, since all the vertical layout will be done later and does not depend on the timestmap. We will have to arrange elements on the canvas vertically in a different order, so we can easily exclude it from the interpolation.

Let's reiterate the formulae:

<code>y = y1 + (x - x1) * ((y2 - y1) / (x2 - x1))
</code>

Considering the explanation above:

  • x1 is the first timestamp from the time span on a screen
  • y1 is the lowest of canvas' x coordinate ( 0 )
  • x2 is the last timestamp from the time span on a screen
  • y2 is the highest of canvas' x coordinate ( canvas.width )
  • x is a numeric timestamp value
  • y is a corresponding x coordinate of that timestamp on canvas

Substitute these in the formulae:

<code>y = 0 + (x - firstTimestamp) * ((canvas.width - 0) / (lastTimestamp - firstTimestamp))
</code>

And simplify it:

<code>y = (x - firstTimestamp) * (canvas.width / (lastTimestamp - firstTimestamp))
</code>

In terms of code, the interpolation function looks like this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scaleX</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(date</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> overallDuration</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> canvasWidth) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((date</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStart) </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (canvasWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> overallDuration))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now, for a given canvas size and time span range we can figure out the x coordinate of any date (even if it is far out from the time span - this will actually give us the ability to scroll the chart). Hence we can start drawing both milestones and current time line (marking "now" on a chart). It is as easy as figuring out the coresponding y coordinate of an object you want to render. For instance, the current time line would start with y = 0 and end at y = canvas.height . The milestone bars, however, could have their y coordinate calculated as y = milestoneIndex * (milestoneHeight + (verticalPadding * 2)) .

And that is what makes the core of the new chart implementation. The rest is a ton of fanciness in form of pretty colors, drag&drop milestones (updating the underlying data) and scaling them, rendering connection lines between them. For the most part it is a combination of plain JS and Canvas API.

The only trick-ier bit is moving and resizing the milestones - if you want to update the underlying milestone data, you will need to have an inverse of linear interpolation above - you will need to figure out the date based on x coordinate on canvas. This is as simple as swapping the parameters in the interpolation: instead of y variable representing the x coordinate on canvas, it should represent the date on the time span and x variable should represent the x coordinate on canvas:

  • y1 is the first timestamp from the time span on a screen
  • x1 is the lowest of canvas' x coordinate ( 0 )
  • y2 is the last timestamp from the time span on a screen
  • x2 is the highest of canvas' x coordinate ( canvas.width )
  • y is a numeric timestamp value
  • x is a corresponding x coordinate of that timestamp on canvas

In JS it looks like this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scaleDate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStart</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> overallDuration</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> canvasWidth) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(minStart</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (overallDuration </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> canvasWidth)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Using Canvas for this project sounds reasonable, especially given the time span can potentially be very large. This also enables rendering nice controls and connection (dependency) lines.

However, the big disadvantage of using Canvas is the complexity to use the custom HTML elements for description or other milestone details (for instance, to show the additional details about mileston - goal, assignee, etc.).

This is the reason this implementation is still not a standalone React component - I am still trying to figure out the best way to render the chart.

Anyhow, that's it for now. I will improve this solution when the time comes.

ShootThem! revival urn:uuid:f3733dc0-69e6-56a9-a073-e85ad3764525 2020-11-13T00:00:00Z 2020-11-13T00:00:00Z

Quite some time ago I dag out the sources of an old game of mine, ShootThem! made back when I was at high-school, around 2006.

It has been over a decade ever since I made that game and I had enough inspiration to revisit the code once again.

This is a short update blog about what it used to be and what it became as of now.

Artem Shubovych

Quite some time ago I dag out the sources of an old game of mine, ShootThem! made back when I was at high-school, around 2006.

It has been over a decade ever since I made that game and I had enough inspiration to revisit the code once again.

This is a short update blog about what it used to be and what it became as of now.

2006

Back in 2006 I have barely learned some OOP and C / C++, just enough to be able to use it in school programming competitions.

The game looked awful - there were no textures in the whole game, the models were mostly hand-made by myself in some dodgy 3D editor (Calligra TrueSpace or something alike).

The code was terrible as well - static variables, huge functions, not to mention the whole game was a huge hard-coded, non-configurable mess in one main.cpp file.

But there was also a map editor, which allowed for some customization - it was basically a first-person camera and few magical buttons that allowed to define target positions for a specific level. The level mesh and output file were both provided via command-line arguments.

2015

I have dag out the sources and decided to put them on GitHub for historical reference. I have also managed to set up CMake for the thing so that it could be built on any computer without bothering too much about magical compiler options and everything.

2020

I have started the rework. First things first, I reworked the CMake configuration to a modern style and replaced the dependency "management" (essentially an instruction to manually unzip Irrlich and IrrKlang files and put them in specific directories) with CMake's Fetch module.

Then I thought about reshaping the code, so I have split one big main.cpp file with static variables and a handful of functions into classes, encapsulating the logic - Level , Score , PlayerState , GameState . This allowed me to maintain the working state of the game whilst actually improving the state of the code ( commit ).

I have also extracted the settings into a separate file, settings.xml so that the application can be actually somewhat configured. Also, the magical data format for the levels was replaced with much more readable XML, levels.xml :

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">levels</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">level</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">model</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">room1.dae</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">model</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">entities</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">light</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">position</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> x</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"-717.96405029296875"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> y</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"129.1875"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> z</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"200"</span><span style="color:#179299;--shiki-dark:#81C8BE">/></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">light</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">light</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">position</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> x</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"0"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> y</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"125.34170532226563"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> z</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"258.18295288085938"</span><span style="color:#179299;--shiki-dark:#81C8BE">/></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">light</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">target</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">position</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> x</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"-765.06158447265625"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> y</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"271.0589599609375"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> z</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"670.49334716796875"</span><span style="color:#179299;--shiki-dark:#81C8BE">/></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">target</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">      &#x3C;!-- ... --></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">entities</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">level</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">levels</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

Next step was to reduce the coupling of code components and introduce some sort of state management. I am still unhappy with what I ended up with, but it is still infinitely better than one single main() function.

I have ended up with something similar to Redux from front-end world (at least that was an initial plan) - there is a Store , where the state is stored; there are Actions , which define a change to the state; there is a Reducer , which modifies the state of the app; and finally, there are Subscribers which react to state changes and render the state of the app.

But the issue was that there are many effects to handle like playing sound, loading and unloading the data, etc.

Along the way I have also kept maintaining a list of things I was thinking about - bugs found, improvements, refactoring ideas, etc ( README.md history ).

Few improvements included adding a main menu, replacing the "UI" with something more user-friendly (previously it was just an ugly line of text), improving the "drunk shooter" effect (ended up replacing it with shaders, which is not a trivial task in Irrlicht - more on that later).

I have also started reworking the 3D models for the game and decided it was a good point to just show how I meant the original art to be in the game:

The art is still far from being ready, but here's a preview of the new training level:

The editor was also reworked... Or better being said, made from scratch - now it actually has a GUI, it allows to manage all the levels without restarting the app, it allows to place targets and move them around, it allows to place light sources on the scene and it is not a first-person camera anymore.

Lessons learned

There are quite a few lessons that I have learned.

CMake sucks. A lot.

I freaking hate CMake for a few very good reasons:

  • awful syntax, it is still same good old Make, just with syntax being wrecked
  • lack of any structure to the projects - everyone does it in their own preferred way, so no one will actually tell you the way to set up your project
  • the lack of dependency managemen - which, in 2020, seems like a huge drawback, especially if you don't develop every single bit of your application from scratch
  • performance - yes, performance - by default it performs a clean build every time - it compiles everything from scratch every time you change anything
  • documentation - no one will tell you the way to do it ; most manuals and articles still rely on CMake 2.6 or 3.0 at best; a lot of information online is so dispersed, inconsistent and out-of-date - you will be surprised!

The only reason I use CMake is because all the dependencies I use could be used with CMake. Well, except Irrlicht and IrrKlang.

I thought Bazel or Buck will be better, but they still require one to create custom build instructions for those dependencies and it is especially hard for a cross-platform libraries such as Irrlicht. Well, at least they do solve most of CMake issues I have listed above.

Irrlicht is old

It is extremely old - last bugfix version, 1.8.4 , was released on 9th July 2016 (which is only 4.5 years ago as of now) and the corresponding minor version, 1.8.0 being released on 8th November 2012 (8 years ago as of now).

It might not seem like a huge deal, but here are few things that I have noticed:

  • shaders are hard to get working
  • only GLSL and HSL are supported
  • no frame buffer support
  • renderers are OpenGL 3 and DirectX 9
  • out-of-the-box tools are quite limited:
    • camera movement is either Maya-style, First-Person-Shooter-style or manual control, through matrices and vectors
    • the GUI out of the box is not suited for high-resolution monitors with fonts being pixelated
    • overall a lot of bugs with GUI (random events missed or fired)
  • ray-picking is buggy
  • textures / lighting is buggy as heck (sometimes textures are disappearing, separate mesh triangles being shaded differently from others, etc.)
  • anti-aliasing not working properly for sprites (which makes my HUD look ugly most of the time, even though it is high-res images)

Check these screenshots for example:

It is the same scene, with lighting being messed up for all target models on the latter screenshot.

With the subset of APIs that are needed for my game, I am quite seriously considering just sticking to lower-level graphics APIs (OpenGL / DirectX) and stepping away from Irrlicht.

C++ is not easy

With the idea of having redux-like state management and the strong type system of C++ I thought it would be a good idea to leverage the compiler and language features to do some compile-time checks for the actions that are being dispatched. I started with templates, but then figured out (the most painful way possible) that templates are merely hints for compiler.

Also, one can not define method overrides for the base class of the hierarchy by specifying child class as method param.

So my initial design like below fell apart very quickly:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PlaySoundAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string filename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DestroyEntityAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shared_ptr</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Entity</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">BaseAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Reducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // error: 'processAction' marked 'override' but does not override any member functions</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DestroyEntityAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">      // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // error: 'processAction' marked 'override' but does not override any member functions</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PlaySoundAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">      // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Store</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">unique_ptr</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">BaseReducer</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> reducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">queue</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">BaseAction</span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> actionQueue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processQueue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">actionQueue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> actionQueue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">front</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        actionQueue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // error: no matching member function for call to 'processAction'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        reducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Templates won't solve the issue either:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // only this method will be called every time</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    template</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> T</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">T</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "processing unknown action"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Reducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">DestroyEntityAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "destroying an object"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">PlaySoundAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "playing a sound"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Also, a template method can't be virtual.

So here comes another trick front-end developers use, the type field for actions and switch..case statement in reducer:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">BaseAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Reducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseReducer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> processAction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">BaseAction</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> override</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      switch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ActionType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PLAY_SOUND</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">          std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "playing a sound"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ActionType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">DESTROY_ENTITY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">          std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "destroying an object"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        break</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">          std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cout </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "unknown action"</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Editor is really important

My game has multiple levels. Each level requires its own lighting and target placement. It is quite hard to do properly without the editor. And the first version of my "editor" has proven that.

Even the new version of editor lacks lots of features - one still can't rotate the targets or see the actual targets, there are no particle emitters available, there are no scene-specific events that would have allowed some neat mechanics.

And finally, it is hard to see the result in the editor itself - there will be differences with the game.

However, I did consider using GoDot engine for the game.

There are features that I really liked about it.

I18n support

Configurable user actions

This way you can have same handler for gamepad buttons' and keyboard/mouse input events:

Attaching scripts to any object on the scene

This allows for a magnitude of interesting mechanics.

For a number of reasons I didn't choose it - there were some user experience issues significantly reducing my productivity.

Asset management

Sspecifically the neccesity to specify every single texture for every single object on a scene. Check out this chicken model:

It is just an OBJ file with every material specified:

<code>mtllib chicken.mtl

# 262 vertex positions
v  18.556948 41.779099 -12.354659
v  20.53804 50.283123 -13.547608

# ...

# Mesh '0' with 68 faces
g 0
usemtl Material #1
f  1/1/1 2/2/2 3/3/3
f  3/3/3 2/2/2 4/4/4

# ...
</code>

Yet in the editor you'll have to manually assign every single material to every single sub-mesh:

Not really clear scene node types

Now which node do I use for kinematic physical body?

Just what the heck is "spatial" and why does it have both "camera" and "collision shape" next to "audio stream"?

Lack of any sort of pre-made solutions

So that every time you need an FPS camera - you have to define it from zero, using the matrix transformations. This increases the amount of boilerplate code and actually reduces the productivity even compared to Irrlicht:

This is not the end

I am not done with this project revival just yet - I still want it to build under OSX and I still have few assets to put into the game. Also, the plot is still not very clear, so I'd better come up with something rather interesting. Stay tuned for more updates!

Erlang example 2.0 urn:uuid:27f7853e-e416-5409-8099-1be7b4959b98 2020-11-07T00:00:00Z 2020-11-07T00:00:00Z

Quite some time ago I've published a blogpost about Erlang . It claimed to present a short intro to distributed programming in Erlang . But it turned to be a very simple communication application, nothing super-exciting.

In this post I would like to elaborate more on the topic of Erlang, for a number of reasons:

  • it is a pretty simple language itself
  • the distributed systems topic gets more and more of my attention these days
  • when I was looking at Erlang, I would love to see a more advanced tutorial myself (more practical things and more Erlang platform features showcased)
Artem Shubovych

Quite some time ago I've published a blogpost about Erlang . It claimed to present a short intro to distributed programming in Erlang . But it turned to be a very simple communication application, nothing super-exciting.

In this post I would like to elaborate more on the topic of Erlang, for a number of reasons:

  • it is a pretty simple language itself
  • the distributed systems topic gets more and more of my attention these days
  • when I was looking at Erlang, I would love to see a more advanced tutorial myself (more practical things and more Erlang platform features showcased)

Language features

Kicking off with the language features, let's discover few data structures available out of the box.

I was thinking for few a while about what could be showcased in Erlang. I think the system we'll develop closer to the end of this blog is quite nice.

Tuples

As you might remember from the quick introduction to Erlang , tuples are defined like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt5 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span></code>

Now, since there are no datatypes or alike in Erlang, we can use tuples to denote complex data structures, like trees, for example:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span></code>

With this, let us create a module to work with binary trees:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">binary_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewNode </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}.</span></span></code>

The idea behind insert_into_tree/2 is that every call has to return the copy of a current tree with a recursively modified leaf.

Now, to test the binary tree, we can define a function that checks if a node is in tree or not:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nil, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#D20F39;--shiki-dark:#E78284"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#D20F39;--shiki-dark:#E78284"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">=:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span></code>

You might want to compile the module now, by running

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$erlc binary_tree.erl</span></span></code>

We can run the program to construct a tree and check if some element is in there:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">binary_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Tree </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 22</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  X1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  X2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  X1Present </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  X2Present </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fwrite</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Tree: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">n"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fwrite</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">p in tree (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">p)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">n"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> X1Present</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fwrite</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">p in tree (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">p)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">n"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> X2Present</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span></code>

This is a bit cumbersome, so let's use the lists:foldl/3 function together with a list of values to construct the tree in a more convenient way:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foldl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Values </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 22</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Tree </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foldl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Elt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Elt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  % ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  .</span></span></code>

Records

There is a mechanism in Erlang called records . It is basically a syntactic sugar around tuples, just as we have used them above, but it gives a little bit more clarity for pattern matching when writing code:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">record</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#179299;--shiki-dark:#81C8BE"> #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewNode </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nil, _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#D20F39;--shiki-dark:#E78284"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#D20F39;--shiki-dark:#E78284"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">=:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Parent </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span></code>

Well, it does make pattern matching more explicit, but the code has just blown up! Luckily, Erlang does provide a syntactic sugar to read a specific field of a record and to update specific record' fields:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right </span><span style="color:#179299;--shiki-dark:#81C8BE">=:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> % read specific fields from Tree, namely - right and value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewNode </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> % update only the tree.right value, leave the rest values of Tree unchanged</span></span></code>

This makes a module a bit shorter again:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">record</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#179299;--shiki-dark:#81C8BE"> #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right </span><span style="color:#179299;--shiki-dark:#81C8BE">=:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewNode </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left </span><span style="color:#179299;--shiki-dark:#81C8BE">=:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewNode </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewNode </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> right </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert_into_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nil, _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#D20F39;--shiki-dark:#E78284"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">=:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">right</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree, Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    is_in_tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tree</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">tree</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span></code>

Maps

Well, having records is good and nice. But what if we want a hashmap? Consider a trie data structure, where it has a value and a map of characters to nodes. Technically, we could have a list of nodes and iterate over them whenever we need to access a specific child. But that would be a waste of time.

Luckily, Erlang does provide the maps module:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foldl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> put</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> contains</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">record</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> children </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#179299;--shiki-dark:#81C8BE"> #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stop </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> children </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Trie, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[])</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Trie</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stop </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">insert</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Trie, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Children </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Trie</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  IsChild </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    IsChild </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      SubTrie </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      NewSubTrie </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SubTrie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      NewChildren </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">put</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewSubTrie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      Trie</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> children </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewChildren </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      SubTrie </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      NewSubTrie </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> insert</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SubTrie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      NewChildren </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">put</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewSubTrie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      Trie</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> children </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NewChildren </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">contains</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Trie, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[])</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Trie</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">contains</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Trie, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Children </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Trie</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">trie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  IsChild </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    IsChild </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      SubTrie </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> maps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      contains</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SubTrie</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Chars</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">      false</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

Quite unfortunately, pretty much none of the handy maps syntax is implemented yet.

Platform features

Let's start with few simple but practical examples.

Web-server

Erlang comes packed with a lot of features. One of them is bundled web-server. Some time ago I've published a post about a very simple Tetris game, which I've crafted one evening. The thing is: that game is nothing more than a single HTML page. What we can do now is start a web server, which will listen for connections on 8080 port and serve them a static file with the game.

The code is pretty simple:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">simple_web_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> run_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> stop_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  inets</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  inets</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">httpd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> port</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8080</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> server_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "httpd_test"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> server_root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "."</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document_root</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "."</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bind_address</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> any </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  inets</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">httpd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span></code>

But modern web applications require a server that will have some sort of an API. Take REST for example - when a URL of a specific format with specific HTTP method ( GET , PUT , POST , DELETE , etc.) is hit on the server, some behaviour is expected. For instance, curl -X GET http://server.address/posts request is expected to return a list of all Post entities (whatever that means in the context of an application), whereas curl -X PUT http://server.address/posts -d '{ "title": "post #1", "content": "blah" }' -H "Content-Type: application/json" is expected to create a Post entity with fields title and content from the request.

The bundled Erlang HTTP server, httpd kind of allows for that, except the URLs will be in a format cgi-bin/erl/mymodule:mymethod , which is not exactly what we want. But just for the sake of example, here's how it would look like implemented with httpd:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">posts</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID, Env, Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mod_esi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deliver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Content-Type:application/json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mod_esi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deliver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> do_get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">do_get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  QueryParams </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> uri_string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dissect_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _IdParamName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> lists</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">search</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "id"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  [</span><span style="color:#40A02B;--shiki-dark:#A6D189">"{</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">:1,</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">post 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">blah</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">}"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID, Env, Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mod_esi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deliver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Content-Type:application/json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mod_esi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deliver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> do_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">do_all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  [</span><span style="color:#40A02B;--shiki-dark:#A6D189">"[{</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">post 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">blah</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">"</span><span style="color:#40A02B;--shiki-dark:#A6D189">}]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID, Env, Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mod_esi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deliver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Content-Type:application/json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mod_esi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deliver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SessionID</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> do_create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">do_create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  % here the Input variable will contain the POST request' body, which will most likely be a JSON, which we also will need to parse</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  [</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Status: 204 No Content"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span></span></code>

As you can see, this is a pretty complex example, since the API of httpd module is rather low-level - we have to explicitly form a HTTP response and send it back to clients. Although not impossible, it is just not so pleasant development experience as it could be. Read on to see how it could be significantly improved.

Mnesia

Erlang is bundled with a distributed real-time database called Mnesia!

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">visit_tracker</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  init</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  create_schema</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  create_account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  find_account_by_email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">record</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> site_id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> browser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> location </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">record</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">site</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account_id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visits </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">record</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sites </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">init</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_schema</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()]),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_schema</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">visits</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> record_info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fields</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> record_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visit </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sites</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bag </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> record_info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fields</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> site</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> record_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> site </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]),</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_table</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">accounts</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bag </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> record_info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fields</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> record_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">%% temporarily forcing to put ID by hand</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id, Email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Txn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %% record creation syntax is similar to dictionary / map creation syntax: `#record_name{ key = Value }`</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">write</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">accounts</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> email </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sites </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> write</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transaction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Txn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_site</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Account, Id, Name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  AccId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Account</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Txn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">read</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">accounts</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AccId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %% mnesia:write(Account),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">write</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sites</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">site</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account_id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> AccId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> visits </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> write</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transaction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Txn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Site, Ip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  create_visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Site</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Ip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> unknown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> unknown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Site, Ip, Browser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  create_visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Site</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Ip</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Browser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> unknown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_visit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Site, Ip, Browser, Location</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  %% retrieving ID field from the Site parameter</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  SiteId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Site</span><span style="color:#179299;--shiki-dark:#81C8BE">#</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">site</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Txn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">read</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sites</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> SiteId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %% since table name is different to record name, we have to pass table name as the first argument</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transaction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Txn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find_account_by_email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Txn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %% select semantics:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %%</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %%   mnesia:select(Table_name, [ Query, Conditions, ResultMapping ])</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %%</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %% here,</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %%  * Query defines the generic pattern to match agains</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %%  * Conditions or Guard is a list of tuples defining the clauses: { operator, field, value }: { '>', 'id', 10 }</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %%  * ResultMapping is what will be returned; you can use the pattern matching from the Query param here</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %%</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    %% map / dictionary creation: #{ key => value }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Acc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">accounts</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> #</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">',</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> email</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sites</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">',</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> email </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sites </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Acc</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mnesia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transaction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Txn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span></code>

Ecosystem

Using Rebar 3 (or Hex for Elixir) is relatively easy. Yet it opens access to thousands of packages available out there.

Creating a project

To create a project with rebar3 support, you can now use rebar3 new &#x3C;template> &#x3C;app-name> . For just an application, you can use app template name. For libraries - use lib . Simple!

To add a dependency, edit the rebar.config file in the application directory and change the deps dictionary:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">epsql</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "~> 4.6.0"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> % PostgreSQL package</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span></code>

Then, since a single project can have multiple applications, one needs to add the dependency to each application which requires that dependency. This is done in the *.app.src file in the application root directory (for instance, myapp/appname/appname.app.src ):

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> appname</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB"> [{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">description</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">registered</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">modules</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">applications</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">kernel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  stdlib</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                  epsql</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mod</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">appname_app</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []}},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">env</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span></code>

Building the project with dependencies is then done using the rebar3 compile command from the project root directory (following the example above, myapp/ ).

To run an application, use the rebar3 shell --apps &#x3C;comma-separated-app-names> from the project root directory (e.g. rebar3 shell --apps appname ).

PostgreSQL

Working with PostgreSQL in Erlang is possible through one of many libraries available in rebar3 repository . In this blog I will use epsql library.

For the most part, when working with the database, you only need a handful of features from the database library:

  • connecting to the database with specific parameters (connection pool size, security options, timeouts, etc.)
  • executing prepared statements (allowing the DB communication layer - the library - to safely inject query parameters, preventing the SQL injection)
  • support for SELECT , INSERT , UPDATE and DELETE statements (with very few exceptions, these form 95% of all the use cases, in my experience)
  • retrieve query results (as list of dictionaries of sorts)

epsql library provides all of these with the following functions:

  • epgsql:connect/1 (and its variations) in combination with epgsql:close/1 to close the connection, if ever needed; epgsql:connect/1 takes a dictionary of options, including
    • host
    • username and password ; optionally - ssl and ssl_opts for secure connections
    • database
    • timeout - for limiting the connection time
  • epgsql:squery/2 and epgsql:equery/3 to query the database
    • epgsql:squery/2 will execute a simple query (takes connection and a query string as parameters, returns a tuple of status - ok or error , list of columns and list of rows)
    • epgsql:equery/3 will create an unnamed prepared statement (yes, you can have named prepared statements for future reuse), safely inject the query parameters (specified as $1 , $2 , $3 and so on in query string, the second argument) passed as the third argument (a list of parameters) and execute the statement on a database connection (passed as the first argument)

Here are few simple examples of the above functions:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">connect_to_blog_db</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> epsql</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">connect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> host </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "localhost"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> username </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "root"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> password </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "****"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> database </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "blog"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_blog</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Title, Content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  C </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> connect_to_blog_db</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Count </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> epsql</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equery</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "INSERT INTO posts (title, content) VALUES ($1, $2)"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Content </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Count </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get_blogs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  C </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> connect_to_blog_db</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Columns</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Rows </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> epsql</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">squery</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "SELECT title, content FROM posts"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

Mochi HTTP server

As shown above, the default HTTP server bundled with Erlang standard library (OTP) is rather low-level. There are few options in rebar3 package repository which significantly improve the situation. One of them is mochiweb .

The web server with Mochi could look like this (slightly more complex than the one described above with httpd ):

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">http_sample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">define</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">HTTP_OPTS</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  [</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">MODULE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> port</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4000</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> http_4000 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Http </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">HTTP_OPTS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Pid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> spawn_link</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  register</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">http_sample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  http_sample </span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">method</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> of</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GET</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get_resource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PUT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> put_resource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> method_not_allowed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get_resource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Path </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  % note: io:format(FmtString, Params) would print to STDOUT</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  % whereas io_lib:format(FmtString, Params) will return a formatted string</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> io_lib</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">format</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Hello, Resource '</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">s'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Path </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Headers </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [{</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Content-Type"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "text/plain"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }],</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">respond</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 200</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Headers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">put_resource</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ContentType </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get_header_value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Content-Type"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ReqBody </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">recv_body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">respond</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 201</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [],</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "201 Created</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">r</span><span style="color:#7C7F93;--shiki-dark:#949CBB">\</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">method_not_allowed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Path </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Method </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">method</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> io_lib</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">format</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Method </span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">s on path </span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">s is not supported"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Method</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Path </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  mochiweb_request</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">respond</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 405</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Req</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ok</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  receive</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ok </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> mochiweb_http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      exit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">normal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ignore</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">MODULE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span></code>

For this code to run, you should do few little extra steps. First, creating the new application with rebar3 - I prefer escript template for something this simple.

Then, add a new dependency to the rebar.config file:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">erl_opts</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">debug_info</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mochiweb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "2.22.0"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> % &#x3C;---- here</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shell</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  % {config, "config/sys.config"},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">apps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">http_sample</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">]}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span></code>

Then, put the code from above under src/http_server.erl file.

Finally, run the interactive shell in the context of the application: rebar3 shell and start server by calling http_server:start(). .

Alternatively, you can compile the program to a binary file using rebar3 compile and then run the program using erl command:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">erl</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -pa</span><span style="color:#40A02B;--shiki-dark:#A6D189"> _build/default/lib/http_sample3/ebin/</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -pa</span><span style="color:#40A02B;--shiki-dark:#A6D189"> _build/default/lib/mochiweb/ebin/</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -noshell</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -s</span><span style="color:#40A02B;--shiki-dark:#A6D189"> http_sample3</span><span style="color:#40A02B;--shiki-dark:#A6D189"> main</span></span></code>

This, however, will immediately stop the execution of a program once the http_sample3:main/0 finishes, so you might want to change the source a bit:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">format</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Hello, server!</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">n"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    http_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(),</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        stop </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> http_server</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    done</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

This way, the http_sample3:main/1 will be called and will wait for the stop signal to be sent to the process. Or until the main erl process is terminated.

Finally you should be able to communicate with this rather simple server by using curl , for example:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">curl</span><span style="color:#40A02B;--shiki-dark:#A6D189"> http://localhost:4000/my/resource</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -X</span><span style="color:#40A02B;--shiki-dark:#A6D189"> PUT</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -d</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '{ "name": "message", "value": "my message" }'</span></span></code>

Summary

This blog was supposed to show Erlang from a slighly different perspective, as opposed to how it was presented to me in uni. I guess you could treat this as a "Practical Erlang" blog.

This post was supposed to be released in mid-2020, but it took me quite a while to polish it. In the next blog I will build this on to provide a much more exciting application sample with Erlang.

Vim keystrokes cheatsheet urn:uuid:78a97cb8-e800-509a-9a8e-f41a074c5fed 2020-08-04T00:00:00Z 2020-08-04T00:00:00Z Vim keystrokes cheatsheet Artem Shubovych

The time has come for me to list few of the commands and keystrokes that I use (and the ones that I don't but would like to start) in Vim.

I am actually running a Vim plugin for Visual Studio Code (this and the previous blogs are actually written with this plugin ON) at this very moment.

Bear 🐻 in mind: this blog is aboout keystrokes only, it is not about plugins or configuration I use - I shall cover that one day.

Things I know by heart

  • h , j , k , l for slow but precise character-wise movement
  • w , b for faster forward (and, correspondingly) backward word-by-word movement
  • $ and ^ to go to the last and first word character of the line
  • gg and G to go to the beginning and the end of the file
  • O (capital o ) to create a blank line and go to INSERT mode above and below (lower-case o ) the cursor
  • f , F and t and T for single character lookup within the current line
  • / and ? to search forwards and backwards
  • c (followed by the object) to change the object ; this expands to the following few commands:
    • cw to change the current word under cursor
    • cit to change the text within the current XML tag
    • ca' to change the text surrounded by single quote
    • ci&#x3C; to change the text surrounded with &#x3C; and >
    • ci{symbol} to change the text surrounded by symbol , which could be ' , " , &#x26;#96; ; you can also use b( for block of text, surrounded by braces, B{ for block of text surrounded by curly braces or p for paragraph, all instead of symbol
  • v to enter the VISUAL mode, followed by the command:
    • v{select}c immediately change the selection
    • v{select}d cut the selected text
  • y and p copy and paste the selected text (lower-case p pastes above the current line, capital-case P pastes below; capital-case Y copies the entire line, so the duplicate line command in Vim is Y, P )
  • {number}{command} repeat the command number times
  • . (the period or dot symbol) repeats the last command
  • x to remove the character under cursor
  • r{char} to replace the character under cursor with char
  • A to go to the end of the line and enter INSERT mode ("append")
  • u and Ctrl+r to undo and redo actions
  • &#x26;gt; and &#x26;lt; adds or removes the indentation

Things that I am still getting used to

  • {number}{motion} instead of h , j , k , l
  • a instead of i to enter INSERT mode after the cursor (as opposed to i which enters INSERT mode before the cursor)
  • H , M and L to go to the top, middle and the bottom of the screen (High, Mid and Low)
  • * and # to search for the word under cursor forwards and backwards
  • {count}/{query}⏎ to go to the count -th occurrence of query ; it is same as searching with / and then hitting n count times
  • gd navigates to a definition of an entity under the cursor
  • gf navigates to the path under cursor
  • % moves the cursor to the matching brace, bracket or curly brace
  • g~ toggle the case
  • = format the selection
  • gU makes the selection uppercase
Gantt chart with D3. Part 2 urn:uuid:438adc75-2fea-5a0b-be9d-fa4f2855dc55 2020-08-02T00:00:00Z 2020-08-02T00:00:00Z

Contents

In the original blog I claimed to implement something like this:

Yet I ended up implementing something more like this:

Does not look quite same, right? It also does not work quite same and lacks few quite important features too.

Don't get me wrong, the original implementation did serve project needs, but it was not something anybody could simply use in their project management software and expect customers to love it.

Hence I came up with these complaints about the implementation:

Namely, there are three main issues that I see:

  1. there is a place for mistakes: milestones are allowed to depend on later milestones or simultaneously going ones
  2. there is no clear distinction between the dates each specific milestone starts or ends
  3. if the milestones overlap with current timeframe, current day is not highlighted on the chart (and that often is useful)

Apart from that, there are few technical challenges preventing his whole thing from becoming a real application component:

  • dependency lines look ugly with those sharp corners
  • the implementation is not based on any framework neither does it declare its dependencies (like D3 or MomentJS)

Now I want to revise the original implementation and make it a bit more usable, just like this:

Artem Shubovych

Contents

In the original blog I claimed to implement something like this:

Yet I ended up implementing something more like this:

Does not look quite same, right? It also does not work quite same and lacks few quite important features too.

Don't get me wrong, the original implementation did serve project needs, but it was not something anybody could simply use in their project management software and expect customers to love it.

Hence I came up with these complaints about the implementation:

Namely, there are three main issues that I see:

  1. there is a place for mistakes: milestones are allowed to depend on later milestones or simultaneously going ones
  2. there is no clear distinction between the dates each specific milestone starts or ends
  3. if the milestones overlap with current timeframe, current day is not highlighted on the chart (and that often is useful)

Apart from that, there are few technical challenges preventing his whole thing from becoming a real application component:

  • dependency lines look ugly with those sharp corners
  • the implementation is not based on any framework neither does it declare its dependencies (like D3 or MomentJS)

Now I want to revise the original implementation and make it a bit more usable, just like this:

The plan for this blog is:

  • Technical improvements
    • revise the implementation into a proper Node package
    • optimize for bundle size
  • Feature improvements
    • render milestone conflicts in different style
    • draw days on a background
    • draw current date, if applicable
    • make lines more like curves

Extracting into a package

Well this one is pretty easy - you just do npm init -y , add dependencies with npm install --save moment d3 and require them in your file.

I went a tiny bit further and also changed few minor syntactic inconsistencies to follow with the more modern ES syntax:

  • using import instead of require()
  • preferring const over let and var
  • replacing the Object.assign with spread operator
  • passing in the default values to the function params instead of constantly checking for null and undefined

Bundling

Although the package declares the dependencies, it does not really use them. Well, it could, but only in case it would be used in the system which defined require() function.

D3 itself is a heavy package. Same applies to moment.js. If you bundle the library with anything (I have used Parcel to do it quickly), you'll see that this relatively small library builds into a 500kB bundle.

I think that is quite ridiculous, so here are few considerations:

  • replace momentjs with something more lightweight
  • import only specific packages from D3 instead of the whole thing

Let us actually start with D3.

The library currently operates on few features from D3:

  • selecting DOM nodes
  • drawing
    • axes
    • lines (actually, multilines or paths)
    • rounded rectangles
    • text
  • scaling values (across timeframe)

These features actually come in just few D3 packages:

  • d3-axis
  • d3-scale
  • d3-select
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> axisBottom </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'd3-axis'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleTime </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'd3-scale'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> select </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'd3-selection'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

By just using these three imports (and using these functions instead of their d3. counterparts), we can half the size of the bundle:

Some of the features (like drawing text) are actually just methods on the selection , provided by d3-select or the path object, provided by d3-path .

Optimizing even more

Currently, moment.js is used for few purposes:

  • parse the dates
  • sort the milestones by dates
  • calculate the length of each milestone based on its start and end dates or either of those and a duration

Moment is quite a heavy thing. For now, let's ignore date parsing and just replace the initial data with the Date object from the native APIs:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(date)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // => date</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">date</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toDate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // => date</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">date</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">subtract</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // => date - x</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">date</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // => date + x</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(string)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // => new Date(string)</span></span></code>

By doing so, we have cut another 60 kB off the bundle!

Before we do hardcore optimizations (getting rid of D3 itself), let us do a bit of feature work first.

Detecting conflicts

To figure out if a given milestone conflicts with any other milestones, we have to traverse its dependencies and check if any of those start on or after the current milestone's start date.

Luckily the internal representation of a milestone already contains that data, so all we have to do is dependencies traversal:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> detectConflicts</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dataCache </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createDataCacheById</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">milestone</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> errorousDependencies </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> milestone</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dependsOn</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">dependencyId</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dataCache[dependencyId]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startDate </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> milestone</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    milestone</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">errors </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (milestone</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">errors </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [])</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">concat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(errorousDependencies</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">errorId</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#40A02B;--shiki-dark:#A6D189"> `Dependency </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">errorId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> must end before this milestone`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> milestone</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Then we can render those milestones with errors and their connectivity lines with different styles:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">errors</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  strokeDash </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '3'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#d33'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">linesContainer</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">selectAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'polyline'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">data</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(polylineData)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'polyline'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'fill'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'none'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stroke)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke-dasharray'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">strokeDash)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'points'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

For milestones themselves we can add a pattern and make it striped:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// error style</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">svg</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'pattern'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'error-fill'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'patternUnits'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'userSpaceOnUse'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '4'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'height'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '4'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'path'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'d'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#d33'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke-width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '1'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bars</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rect'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rx'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ry'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'y'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">width)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'height'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">height)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'fill'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">errors</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'url(#error-fill)'</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#ddd'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'black'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Displaying days on a background

We can leverage the features of a time scale that D3 provides us with to render the days on a background.

The scale, however, is not that easy - it operates on dates, so the width of each day is something we will have to calculate ourselves. It also might have extra ticks in between days (for the month change, for instance) - and that is something I am yet to overcome.

Long story short, before rendering the milestones and their connectivity lines, we can add a bunch of semi-transparent rectangles:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> grid </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(xAxis)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">grid</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">selectAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rect'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">data</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(xScale</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ticks</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rect'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> xScale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'y'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'height'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgHeight)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xScale</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ticks</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'fill'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#dedede30'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

As you can see, the width of a rectangle is being calculated based on the total width of an svg container and the amount of scale's ticks .

One little change to this implementation that I would like to see is alteration in rectangles' colors:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">grid</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">selectAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rect'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">data</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(xScale</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ticks</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rect'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> xScale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'y'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'height'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgHeight)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xScale</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ticks</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'fill'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#dedede30'</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#dedede00'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Highlighting the current date

Right before we draw the rectangles and even the axis itself (again, to prevent the overlapping), we can draw a line showing the current date, if it fits into the range of the chart. For this we can also leverage the properties of the xScale , this time .range() , which returns a two-element array, denoting the beginning and end values of the scale. Of course, we will have to convert the current date to the value on that scale too:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nowOnScale </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> xScale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Date</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">now</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (nowOnScale </span><span style="color:#179299;--shiki-dark:#81C8BE">>=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xScale</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">range</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nowOnScale </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xScale</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">range</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  grid</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'line'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nowOnScale)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'y1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x2'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nowOnScale)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'y2'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgHeight)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'rgb(232, 102, 102)'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke-width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

To be continued

The source code of this implementation could be found on Github .

I think that is enough for now, but it is not the end! There's still some work to be done in removing the D3 from this setup completely, which is actually done in Gantt chart: part 3 blog.

Erlang in 5 minutes urn:uuid:2ddd7260-e73f-52da-80fb-252b30321711 2020-01-10T00:00:00Z 2020-01-10T00:00:00Z Erlang in 5 minutes Artem Shubovych

X = erlang, Y = 5, io:format("Learn ~s in ~s minutes", [ X, Y ]).

Welcome to a 5-minute Erlang introduction!

First things first:

  • Erlang is a functional programming language
  • erl is the REPL shell
  • Ctrl + G and then q or q(). to exit the shell
  • c(file_name). to load the code from file

Now, to the language constructs:

  • every statement has to end with a dot ( . ) symbol
  • multiple statements are separated by comma ( , ) character
  • constants start with a C apital L etter
  • atoms (yes, like in Ruby) start with l owercase l etter
  • atoms are allowed to contain spaces (sic!), but then they have to be quoted: 'atoms are awesome'
  • atoms can also have the at sign ( @ )
  • anonymous functions are defined as fun() -> return_statement end.
  • last statement before end must not end with comma
  • function signature is function_name/number_of_arguments : factorial/1 , format/2
  • comments start with percent ( % ) symbol
  • lists are [ TheOnlyElement ] or [ Head | TailElements ] , where TailElements is also a list
  • pattern matching just works [ Head1 | Head2 | Tails ] = [ 1, 2, 3, 4 ]
  • strings are just "strings"
  • tuples are quirky { elt1, elt2 }
  • maps are even weirder #{ key => value }
  • operators are almost fine:
    • comparison: &#x3C; (less than), > (greater than), >= (greater than or equals to), =&#x3C; (equals to or less than), == (equals to), /= (not equals to), =:= (adds type checking on tops, JS equivalent of === )
    • assignment / pattern matching: =
    • math: + , - , * , / , div , rem (Pascal way)
    • typechecking: is_atom/1 , is_function/1 , is_number/1 , is_boolean/1 , is_pid/1 , is_list/1 , etc.
  • list comprehentions are similar to lists: [ N || N &#x3C;- [ 1, 2, 3, 4, 5 ], N rem 2 == 0 ].
  • files are modules, defined with few statements:
    • -module(module_name).
    • -export([ list_of_function_signatures ]).
    • -import(module_name, [ list_of_functions ]).
  • calling module's export be like module_name:function_name(arguments).

Quick recap:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">%%% module comment</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">erlang_example</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% exporting the functions from the module</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% importing the functions from the other module</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">import</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">my_other_module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> new_factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% constants with pattern matching - will assign the value to non-defined constant on success</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% redefinition is prohibited</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">. </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% exception</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% functions can also be constants</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PlusOne </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> X </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% or, multiline</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PlusTwo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  X </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% the standard way</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bad_factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  N </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">%% function documentation</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% functions can have *guargs*, which are basically pattern matching</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% also, function overloading is split with semicolon (;)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N </span><span style="color:#179299;--shiki-dark:#81C8BE">=&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% last overload ends with dot (.)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% some return types</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">string_fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#40A02B;--shiki-dark:#A6D189"> "hello, world!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">list_fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "elements could be of different types too"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> atom </span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">function_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> X mod </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dict_fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "key"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">14</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">tuple_fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "elt 3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">%% note how overriden_function/1 has different definition than overriden_function/2</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">overriden_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  overriden_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">% the power of pattern matching!</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">overriden_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">overriden_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head1 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head2 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head1 </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">overriden_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tail </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  overriden_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tail</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Head</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">overriden_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, Acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A, B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A </span><span style="color:#179299;--shiki-dark:#81C8BE">=&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A, B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A, B, C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  X </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A, B, C, D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  X </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">C</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  complex_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fst</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> First</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> First</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">snd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Second </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">evens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> X </span><span style="color:#7C7F93;--shiki-dark:#949CBB">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> X </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> X </span><span style="color:#179299;--shiki-dark:#81C8BE">rem</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ].</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">#</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Key </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span></code>

There also are few good resources on this: [ https://learnxinyminutes.com/docs/erlang/](Learn X in Y minutes (where X = erlang)) and [ http://erlang.org/doc/apps/inets/http_client.html](Official Erlang docs).

A response to response to hello world urn:uuid:327393a9-c2c7-50fc-930a-06096d388297 2020-01-10T00:00:00Z 2020-01-10T00:00:00Z

Recently I've received an email from StackOverflow newsletters with a link to a quite controversial (at first glance) blog, A response to Hello World by Caleb Doxsey. This blog is a response to another curious read, Hello world by Drew DeVault.

In the former article, author compared the performance of a tiny "Hello, World" program in Assembly to the same program in Go. He then tried to optimize the program in Go to run faster and towards the end of an article comes up with a program that is faster than its Assembly counterpart.

And this totally makes sense, since if you take a close look at the code, you will notice that author did optimize the program in Go but did not do that for the Assembly code.

I have decided to burn few hours of my life and jump onto this topic, since, in my opinion, author did not do a fair comparison.

Artem Shubovych

Recently I've received an email from StackOverflow newsletters with a link to a quite controversial (at first glance) blog, A response to Hello World by Caleb Doxsey. This blog is a response to another curious read, Hello world by Drew DeVault.

In the former article, author compared the performance of a tiny "Hello, World" program in Assembly to the same program in Go. He then tried to optimize the program in Go to run faster and towards the end of an article comes up with a program that is faster than its Assembly counterpart.

And this totally makes sense, since if you take a close look at the code, you will notice that author did optimize the program in Go but did not do that for the Assembly code.

I have decided to burn few hours of my life and jump onto this topic, since, in my opinion, author did not do a fair comparison.

The original code Caleb has used is (I have added the imports and package declaration required to run the program):

Original Go version

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">package</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> main</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "strconv"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "os"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strconv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Atoi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">os</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">:=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        os</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Stdout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Write</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">byte</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"hello world</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Assembly for original Go version

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> atoi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">helloloop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, len</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, msg</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    syscall</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    dec</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    cmp</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .helloloop</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">60</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    syscall</span></span></code>

Optimized Go version

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">package</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> main</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "strconv"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "os"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "bufio"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ </span><span style="color:#179299;--shiki-dark:#81C8BE">:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strconv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Atoi</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">os</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    w </span><span style="color:#179299;--shiki-dark:#81C8BE">:=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bufio</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">NewWriter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">os</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Stdout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    defer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Flush</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">:=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Write</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">byte</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"hello world"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

What Caleb did was string concatenation in memory, creating a big string in memory and then called the system function to print it out all at once. Indeed, this is way more performant than making an IO syscall every iteration for a short string.

Since Caleb did not provide an equal optimized code in Assembly, I decided to fill this gap. I have spent quite some time (predominantly because I am quite rusty with Assembly at the moment and I forgot that different operating systems use different calling conventions ). I came up with the code in Assembly that does exactly the same as what the optimized Go version does - allocate the memory, fill it with the repeated "hello world" string and then make a syscall to print it to the console.

My optimized Assembly version

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; compile me on OSX: nasm -fmacho64 helloworld.asm &#x26;&#x26; ld helloworld.o -lSystem -macosx_version_min 10.13</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; compile me on Linux: nasm -felf64 helloworld.asm &#x26;&#x26; ld helloworld.o # AND DO NOT FORGET TO ALIGN WITH THE SYSCALL CONVENTION BY USING STACK INSTEAD OF REGISTERS</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">global _main</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">extern _malloc, _puts, _atoi, _free</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">load_counter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    cmp</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .exit_failure</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r13</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _atoi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r13</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculate_memory_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, len</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    imul</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    inc</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">allocate_memory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _malloc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    test</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jz</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .exit_failure</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat_message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat_message_1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    lea</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, len</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    cld</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">copy_message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    inc</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    inc</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    dec</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jnz</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .copy_message</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat_message_2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    dec</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jnz</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .repeat_message_1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">print_string_builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _puts</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">free_memory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _free</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exit_success</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .exit</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exit_failure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x02000001</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    syscall</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .data</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> db</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> "Hello, world", </span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equ</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $ - msg</span></span></code>

My version with logs

As Caleb highlights in his blog, a lot of "burden" is often introduced by many programming languages (referring to the original blog by Drew DeVault) - the debugging and safety-related information.

I went ahead and added few logs, memory deallocation and test for allocation success to the code in Assembly:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; compile me on OSX: nasm -fmacho64 helloworld.asm &#x26;&#x26; ld helloworld.o -lSystem -macosx_version_min 10.13</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; compile me on Linux: nasm -felf64 helloworld.asm &#x26;&#x26; ld helloworld.o # AND DO NOT FORGET TO ALIGN WITH THE SYSCALL CONVENTION BY USING STACK INSTEAD OF REGISTERS</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">global _main </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; a function declaration - an entry point; use `_start` for Linux</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">extern _malloc, _puts, _atoi, _printf</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">load_counter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> r13</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    cmp</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; check ARGC - program takes exactly ONE argument, so checking if ARGC == 2 (first one being program name)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jne</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .exit_failure</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; log</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; store ARGC in R12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r13</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; store the ARGV[2] (by addressing it with *(ARGV + 1)) in R13</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; preserve all the used registers on stack - required by OSX calling convention</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdx</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, log1 </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; copy format string to RDI</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; copy first argument for _printf to RSI</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; copy second argument for _printf to RDX</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; zero out RAX to enable variable function arguments</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _printf </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; syscall to printf()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdx</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; restore the registers' values</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; end log</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; mov r12, rsi ;; pointer to argv (which is a pointer on its own)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; move the address of argv[1] (r12 + 0 => argv[0], r12 + 8 => argv[1]) to rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _atoi </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; convert char* argv[1] to int and store the result in rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r13</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; store counter as int in r13</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; log</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, log2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _printf</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; end log</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">calculate_memory_length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ;; rdi = counter * len</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, len</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    imul</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    inc</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; +1 for the terminal character (\0)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; store total length in r12</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">allocate_memory</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; number of bytes to allocate</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _malloc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    test</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; test the return code of _malloc syscall</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jz</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .exit_failure </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; if it is an error - go to exit(1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> r12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; store address in r12</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat_message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r13</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; set outer loop counter to COUNTER</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; set destination address to the stored address from malloc call</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat_message_1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; push outer loop counter onto stack - we don't need it just yet, but will need it after the inner loop is done</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    lea</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">rel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; load address of our message to repeat into the source address</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, len </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; set inner loop counter to the length of a message</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    cld</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; reset the string copying direction flag</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">copy_message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rsi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; load the next byte from the source memory</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; copy the loaded byte to the destination memory</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    inc</span><span style="color:#D20F39;--shiki-dark:#E78284"> rsi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; advance source pointer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    inc</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; advamce destimation pointer</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    dec</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; decrease the inner loop counter</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jnz</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .copy_message</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat_message_2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; restore the outer loop counter</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    dec</span><span style="color:#D20F39;--shiki-dark:#E78284"> rcx</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; decrement the outer loop counter</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jnz</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .repeat_message_1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; put \0 at current RDI</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">print_string_builder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">r12</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; set first argument to the allocated memory start</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _puts</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exit_success</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    xor</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; exit argument - exit status - 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> .exit</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exit_failure</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rdi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">exit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x02000001</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ;; syscall id - exit; use `60` for Linux</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    syscall</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .data</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> db</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> "Hello, world", </span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equ</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $ - msg</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> db</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> "argc = %d, argv[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] = %s", </span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> db</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> "atoi = %d", </span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span></code>

Comparison

Finally, I ran the aforementioned programs with the following arguments: 1M , 2.5M , 5M , 7.5M , 10M , 12.5M , 15M and 17.5M (where M stands for "million", meaning it will print out X millions of "hello world" strings).

The results became more reasonable:

N Go v1 ASM v1 Go v2 ASM v2
1000000 1.395 0.837 0.51 0.03
2500000 2.36 2.1 0.094 0.062
5000000 4.201 4.203 0.171 0.113
7500000 6.197 6.238 0.26 0.17
10000000 8.355 8.226 0.335 0.219
12500000 10.571 10.359 0.458 0.258
15000000 12.554 13.388 0.498 0.319
17500000 14.529 14.625 0.575 0.347

If you look closely, you would notice the ASM v2 version (the optimized Assembly version) is faster than optimized Go version.

Linq is awesome, right? urn:uuid:17f9bdb2-3dd1-5a7c-9e4f-b84f6980a2a1 2019-12-11T00:00:00Z 2019-12-11T00:00:00Z

Recently I've seen a curious blog on Dev.to, C# and .NET Core Appreciation Post. The most beautiful piece of code I have ever seen... this month! .

In short, author was amazed by how beautiful Linq is, supporting their feelings with this code snippet:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">              join</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens </span><span style="color:#179299;--shiki-dark:#81C8BE">on</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">equals</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">              where</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">              select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Let's tear this example apart and check how really performant beautiful Linq is!

Artem Shubovych

Recently I've seen a curious blog on Dev.to, C# and .NET Core Appreciation Post. The most beautiful piece of code I have ever seen... this month! .

In short, author was amazed by how beautiful Linq is, supporting their feelings with this code snippet:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">              join</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens </span><span style="color:#179299;--shiki-dark:#81C8BE">on</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">equals</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">              where</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">              select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Let's tear this example apart and check how really performant beautiful Linq is!

The boilerplate code to make the thing not fall apart:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> System</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Collections</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Generic</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> System</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Linq</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserId </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Context</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    join</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens </span><span style="color:#179299;--shiki-dark:#81C8BE">on</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">equals</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    where</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MainClass</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">        Context</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> context </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Context</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Users</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1001"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Users</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1002"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Users</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1006"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tokens</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1002"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Weirdo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tokens</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1001"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Waldo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // at this point we want to start counting accesses from scratch</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"---"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"User by token {0} = {1}"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Waldo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Waldo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

I am going to modify it slightly for the sake of metrics a bit later, but first let us see what code does C# generate in order for those magical SQL-like operators to do their thing. I am using https://sharplab.io/ for that purpose.

The code generated for Context#GetUserByToken :

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CompilerGenerated</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sealed</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class &#x3C;>c__DisplayClass2_0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bool &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">b__3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x3C;>f__AnonymousType0&#x3C;User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Token> &#x3C;>h__TransparentIdentifier0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h__TransparentIdentifier0</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Serializable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CompilerGenerated</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sealed</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class &#x3C;>c</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> &#x3C;>c &#x3C;>9 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Func&#x3C;User, string> &#x3C;>9__2_0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Func&#x3C;Token, string> &#x3C;>9__2_1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Func&#x3C;User, Token, &#x3C;>f__AnonymousType0&#x3C;User, Token>> &#x3C;>9__2_2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Func&#x3C;&#x3C;>f__AnonymousType0&#x3C;User, Token>, User> &#x3C;>9__2_4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">b__2_0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">b__2_1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> &#x3C;>f__AnonymousType0&#x3C;User, Token> &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">b__2_2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f__AnonymousType0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> User &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">b__2_4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x3C;>f__AnonymousType0&#x3C;User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Token> &#x3C;>h__TransparentIdentifier0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h__TransparentIdentifier0</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c__DisplayClass2_0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">token </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_1 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_2 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">f__AnonymousType0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;&#x3C;></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">f__AnonymousType0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_4 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;&#x3C;></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">f__AnonymousType0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

If you format it a bit, you might see few issues with it:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c__DisplayClass2_0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">token </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_1 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                    &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_2 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#04A5E5;--shiki-dark:#99D1DB"> &#x3C;></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">f__AnonymousType0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;&#x3C;></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">f__AnonymousType0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c__DisplayClass2_.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                &#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_4 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">9__2_4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;&#x3C;></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">f__AnonymousType0</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b__2_4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        )</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now remove those mangled names:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CompilerGenerated</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sealed</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Result</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IsMatching</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Serializable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CompilerGenerated</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> sealed</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> c</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> readonly</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> c</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cInstance </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetUserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> string &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetTokenUserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Pair&#x3C;User, Token> &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">MakeUserTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    internal</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> User &#x3C;GetUserByToken></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetUserFromUserTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    Result</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">token </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn1 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cInstance.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn2 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cInstance.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetTokenUserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn3 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn3 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cInstance.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MakeUserTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ),</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IsMatching</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn4 </span><span style="color:#179299;--shiki-dark:#81C8BE">??</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Func</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cInstance.</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserByToken</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GetUserFromUserTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        )</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And, simplifying everything with lambdas:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    user </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    token </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            userTokenPair </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">First</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        )</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

If you have not noticed the issue just yet, continue reading.

Now I am adding a simple debug output to check the calls LINQ makes whenever we call Context#GetUserByToken . To do that, I am simply going to smash Console.WriteLine statement to each getter of both User and Tag classes:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        get</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"User&#x3C;{0}>.Id was accessed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        set</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserId </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        get</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Token&#x3C;{0}>.UserId was accessed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        set</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _UserId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        get</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Token&#x3C;{0}>.Body was accessed"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        set</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _Body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Seems like LINQ goes through all users and all their tokens:

<code>---
Token&#x3C;Weirdo>.UserId was accessed
Token&#x3C;Waldo>.UserId was accessed
User&#x3C;1001>.Id was accessed
Token&#x3C;Waldo>.Body was accessed
User&#x3C;1002>.Id was accessed
Token&#x3C;Weirdo>.Body was accessed
User&#x3C;1006>.Id was accessed
</code>

If I was to add one more user like this

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Users</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1008"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span></code>

then the lookup iterates over those ones too:

<code>---
Token&#x3C;Weirdo>.UserId was accessed
Token&#x3C;Waldo>.UserId was accessed
User&#x3C;1001>.Id was accessed
Token&#x3C;Waldo>.Body was accessed
User&#x3C;1002>.Id was accessed
Token&#x3C;Weirdo>.Body was accessed
User&#x3C;1006>.Id was accessed
User&#x3C;1008>.Id was accessed
</code>

If I assign a token to that user, it also will be visited:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tokens</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1008"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Quattro"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span></code>
<code>---
Token&#x3C;Weirdo>.UserId was accessed
Token&#x3C;Waldo>.UserId was accessed
Token&#x3C;Quattro>.UserId was accessed
User&#x3C;1001>.Id was accessed
Token&#x3C;Waldo>.Body was accessed
User&#x3C;1002>.Id was accessed
Token&#x3C;Weirdo>.Body was accessed
User&#x3C;1006>.Id was accessed
User&#x3C;1008>.Id was accessed
Token&#x3C;Quattro>.Body was accessed
</code>

And it is quite well reflected in the generated code - LINQ essentially generates a list of pairs for every user and token matching a join condition:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        user </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        token </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                tempCollection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            userTokenPair </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">First</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        )</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

If we continue extracting the calls to Enumerable , we will end up with something like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        user </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        token </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> matchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        tempCollection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformedMatchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        matchingPairs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        userTokenPair </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">First</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        transformedMatchingPairs</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now, Enumerable.Join is the only tricky instruction here. It makes that big temporary join table (talking SQL and relational databases). It can be written as follows:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                tempCollection</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> matchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        tempCollection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformedMatchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        matchingPairs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        userTokenPair </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">First</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        transformedMatchingPairs</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The Enumerable.Where call simply filters the collection:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                tempCollection</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> matchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            matchingPairs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformedMatchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Select</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        matchingPairs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        userTokenPair </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">First</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        transformedMatchingPairs</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The Enumerable.Select call maps the collection onto some other collection:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                tempCollection</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> matchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            matchingPairs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformedMatchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> matchingPairs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        transformedMatchingPairs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">First</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Enumerable</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SingleOrDefault</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        transformedMatchingPairs</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And finally, Enumerable.SingleOrDefault returns the first element of the collection or the default value ( null in this case):

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                tempCollection</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">>></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> matchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tempCollection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Second</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            matchingPairs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformedMatchingPairs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Pair</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> userTokenPair </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> matchingPairs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        transformedMatchingPairs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">userTokenPair</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">First</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">transformedMatchingPairs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Size </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformedMatchingPairs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

If we remove the unnecessary (for us as the developers) transformations and intermediate collections, we will end up with the code, similar to the naive implementation of the same logic with two nested loops:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchedToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchedToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Except the naive implementation not generating a whole lot of code:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchedToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Enumerator enumerator </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Users</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetEnumerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    try</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">enumerator</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">MoveNext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> current </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> enumerator</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Current</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Enumerator enumerator2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tokens</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetEnumerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            try</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">enumerator2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">MoveNext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">                    Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> current2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> enumerator2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Current</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">current2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> current</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> current2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> searchedToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> current</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            finally</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                ((</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IDisposable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">enumerator2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Dispose</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    finally</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ((</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IDisposable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">enumerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Dispose</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The real difference, however, is in the exact environment the code is running in:

<code>---
Token&#x3C;Weirdo>.UserId was accessed
User&#x3C;1001>.Id was accessed
Token&#x3C;Waldo>.UserId was accessed
User&#x3C;1001>.Id was accessed
Token&#x3C;Waldo>.Body was accessed
</code>

So in the good-case-scenario, naive implementation beats does fewer operations than the LINQ code.

The issue with both approaches is in the worst-case-scenario, which, as I have learned by heart, is the only possible scenario. They both are going to run in O(n^2) time at worst.

Let's consider a small optimization, using indexes :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Context</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserByToken </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserById </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dictionary</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> AddUser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">User</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      Users</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      UserById</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> AddToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Token</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      Tokens</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      UserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserById</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UserId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> GetUserByToken2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// then the main method needs to be adjusted correspondingly:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MainClass</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">        Context</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> context </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Context</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">AddUser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1001"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">AddUser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1002"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">AddUser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1006"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">AddUser</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> User</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1008"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">AddToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1002"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Weirdo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">AddToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1001"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Waldo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">AddToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Token</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"1008"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Quattro"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // at this point we want to start counting accesses from scratch</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"---"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"User by token {0} = {1}"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Waldo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> context</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetUserByToken</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Waldo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Essentially, whenever we add any user or tag, we put them in a dictionary (an index) in memory.

Okay, we sacrifice some memory, but do we earn anything from it?

The output of the program is very short:

<code>User&#x3C;1001>.Id was accessed
User&#x3C;1002>.Id was accessed
User&#x3C;1006>.Id was accessed
User&#x3C;1008>.Id was accessed
Token&#x3C;Weirdo>.Body was accessed
Token&#x3C;Weirdo>.UserId was accessed
Token&#x3C;Waldo>.Body was accessed
Token&#x3C;Waldo>.UserId was accessed
Token&#x3C;Quattro>.Body was accessed
Token&#x3C;Quattro>.UserId was accessed
---
User by token Waldo = User
</code>

So essentially, no collection is iterated. The access to the required object is immediate.

One might argue that the examples here are very synthetic and do not showcase anything. But imagine a real product with millions or even billions of entities like those. Think an average Google-size organization using Jira. Now replace User with Issue and Token with Comment . I can assure you, the numbers would be 10-folded.

Contra: the code is written to be read (more often than not) and deleted (my favourite scenario). So even thought hashmaps might seem appealing, indexing on few more fields might make the code hard to maintain. This is especially crucial for long-lasting projects, where developers come and go as the time passes. So sometimes this might be a necessary evil.

But sometimes it is best to know the theory rather than the tool.

Partial application vs currying urn:uuid:4463d62a-82ba-5919-bc50-62c8949df4b4 2019-03-20T00:00:00Z 2019-03-20T00:00:00Z Partial application vs currying Artem Shubovych

Here's a quick explanation of the difference between currying and partial application .

For a one- or two-argument functions there is little to none difference. But for function with multiple arguments...

Say you have a function f(a1, a2, a3, a4) (it does not really matter what it returns or what the arguments are):

  • currying it will give you a function of one argument, which will return a function of one argument (and so on and so forth), calling which (the last one-argument function) will give you same result as calling the original function f with all the arguments of single-argument functions passed at once (curried) : curry(f) = f1(x1) => f2(x2) => f3(x3) => f4(x4) === f(x1, x2, x3, x4)

  • partially applying a function to some N values will give you a function of smaller amount of arguments, where the first N arguments are already defined: papply(f, 1, 17) => f1(x3, x4) === f(1, 17, x3, x4)

In Javascript, the two could be implemented like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> curry</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> curry</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> currySub</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // Surprisingly, `fn.length` returns the number of arguments of a function `fn`</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (args</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fn</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> currySub</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">concat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([ x ]))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> currySub</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> papply</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> arguments[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(arguments)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">slice</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Array</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(arguments)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args0</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">concat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(args1)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Type casts in C++, explained urn:uuid:073a0a63-c578-5fd9-a431-34480badf443 2019-03-10T00:00:00Z 2019-03-10T00:00:00Z Type casts in C++, explained Artem Shubovych

As explained by my colleague, former professional C++ developer (now writes schwifty Java). Below is a quick explanation of four basic C++ type casts. Just for the matter of shorter post, consider each cast taking a template type T and a parameter value v like this: const_cast&#x3C;T>(v) .

  • const_cast - removes the const from the type of v (think of casting const char* will produce char* )
  • static_cast - C-style, unchecked explicit type casting (just like in old 90s: (int) 3.14 )
  • reinterpret_cast - hard low-level treating a block of memory as type T , no matter what resides in that memory
  • dynamic_cast - does the runtime checks of param type and template type
Game development with Newton Game Dynamics and Irrlicht tutorial urn:uuid:e0340069-b4e7-53a4-9e6e-842a3dcccf60 2018-10-15T00:00:00Z 2018-10-15T00:00:00Z Game development with Newton Game Dynamics and Irrlicht tutorial Artem Shubovych
Slowpoke image

As there was not a high load on my tutorial on game development with Irrlicht and Newton Game Dynamics engines as a separate site, I have decided to merge them with my blog and proceed with occasional updates to both as a whole.

So far, these are the changes to the tutorial in comparison to what it used to be (long time ago) :

  • moved all the build instructions to CMake
  • added scripting with Lua
  • upgraded the whole tutorial to match latest Irrlicht and Newton versions
  • added chapter on modelling with Blender

The things which are already done (just not published yet), in progress and the future plans for this tutorial include:

  • comparison of different build systems for C++ (including CMake , Bazel and Buck )
  • a better approach to application architecture (plus the comparison of different scripting languages - AngelScript , Squirrel , Lua , ChaiScript and Python )
  • a sane 3D modelling in blender lessons (preserving texturing and adding advanced materials, possibly even animation!)
  • advanced topics in Newton Game Dynamics featuring character controller and joints

Tutorial chapters (yet to be updated) :

  • Introduction
  • <code>    &#x3C;li>
            &#x3C;a href="/irrlicht-newton-tutorials/2015/08/26/application-architecture.html">
                Application architecture
            &#x3C;/a>
        &#x3C;/li>
    
        &#x3C;li>
            &#x3C;a href="/irrlicht-newton-tutorials/2015/08/27/first-application.html">
                First application
            &#x3C;/a>
        &#x3C;/li>
    
        &#x3C;li>
            &#x3C;a href="/irrlicht-newton-tutorials/2015/08/28/first-script.html">
                First script
            &#x3C;/a>
        &#x3C;/li>
    
        &#x3C;li>
            &#x3C;a href="/irrlicht-newton-tutorials/2015/08/29/prepare-to-add-some-newtonianity.html">
                Let's add some physics
            &#x3C;/a>
        &#x3C;/li>
    
        &#x3C;li>
            &#x3C;a href="/irrlicht-newton-tutorials/2015/12/15/making-simple-level-with-blender.html">
                Modelling simple level with Blender3D
            &#x3C;/a>
        &#x3C;/li>
    
        &#x3C;li>
            &#x3C;a href="/irrlicht-newton-tutorials/2015/12/16/finishing-the-first-scene.html">
                Finishing the first scene
            &#x3C;/a>
        &#x3C;/li>
    &#x3C;/ul>
    </code>
One-night games: snake urn:uuid:74b286b0-6e15-5c38-a690-a8a9eec28fcb 2018-06-01T00:00:00Z 2018-06-01T00:00:00Z

source code

Under the cut you can find the interesting algorithmic solutions I've mentioned.

Artem Shubovych

source code

Under the cut you can find the interesting algorithmic solutions I've mentioned.

Snake

Source code

Snake is a very simple game to implement. The core is the field, which is a binary matrix of whether there is something to draw in a specific position or there is nothing. The game is tightly bound to the timer, since it is almost a turn-based game and the movement speed should increase as the snake grows. The only things which might be interesting are: snake movement (in other words, how do we update the game matrix on each timer tick) , snake growth (or what happens when a snake collides with the food) and the collision test (or how to determine what the snake collided with) .

The snake movement is quite simple - try thinking of a snake as of a stack of Vector2 objects, having just the coordinates of each body part of a snake:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Point</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    equals</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">other</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> other</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> other</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Snake</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">points</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> direction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> maxX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> maxY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> points</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">direction </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> direction</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxX </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxY </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    advance</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">shift</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nextPoint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    nextPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">last</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">direction </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'up'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            y</span><span style="color:#179299;--shiki-dark:#81C8BE">--</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">direction </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'right'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            x</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">direction </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'down'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            y</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">direction </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'left'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            x</span><span style="color:#179299;--shiki-dark:#81C8BE">--</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (x </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (x </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxX) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (y </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (y </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxY) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Point</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

On every timer tick we should "advance" the snake in the direction of movement by simply adding a new element to the top of a stack and remove the last one, representing snake's tail. When a player hits any of the arrow keys, we simply set the movement direction for a snake, which will be considered on a next timer tick:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Game</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> cols</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cols</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">score </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_createSnake</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">food </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_generateFood</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    updateState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nextSnakePoint </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nextPoint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">food</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equals</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(nextSnakePoint)) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">score</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(nextSnakePoint)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">food </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_generateFood</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">advance</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

There is a need for one more bounds check: when a snake is about to cross the boundaries of a game field, we need to change the next point a snake is about to advance to the opposite "wall" (if we want such a feature) .

The game ends when a snake hits one of its body parts. The check for that is really simple: we just need to check whether the next point is contained in the stack of a snake:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isGameOver</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nextPoint</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">equals</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(p))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

To render a field, we need to render the food and each of snake's body parts:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Renderer</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    _render</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_clearCanvas</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">snake</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points[i]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_drawRectangle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_drawRectangle</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">food</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">game</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">food</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cellSize)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Tetris

Source code

The most interesting part about tetris was to implement piece rotation. I've represented all the possible figures as a list of matrices.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FIGURES </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The problem however is that all figures are different, hence all the matrices have different dimensions - a "stick" is 4x1, whilst a "cube" is 2x2. Other pieces are 3x2. Rotation algorithm might not be simple. And it implies one limitation - pieces should preserve their position - not to move to the sides when rotating them.

Pieces are best represented as matrices, but in order to operate on matrices we need to have the corresponding methods. I decided to just implement the class Piece with the essential methods:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Piece</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> col</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">piece </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">slice</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(shape)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">col </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> col</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Here row and col describe the position of a piece on a screen whilst rows and cols are the dimensions of a piece. piece contains the matrix data of a piece.

The rotation algorithm I've implemented tries to transpose piece's matrix in a very simple manner:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Piece</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    rotate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result[i]) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                result[i] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                result[i][t] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure[t][</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

What it does is actually creating a totally new matrix, where the dimensions are swapped and the data is the opposite data to what was in the original matrix. In other words, we iterate the original matrix over its normal indices, but write the data to the new matrix in the reversed direction. So if we read the row with index 0 and column with index 2 , this means we need to write the data from the source matrix at data[0][2] to the destination matrix at data[2][0] . Sounds correct, right?

But if we do that with the array, we will end up having the new matrix mirrored:

<code>           given:

      0   1   2   3
    +---+---+---+---+
 0  | 1 | 2 | 3 | 4 |
    +---+---+-------+
 1  | 5 | 6 | 7 | 8 |
    +---+---+---+---+


            expectation:

      0   1                0    1
    +---+---+             +---+---+
 0  | 4 | 8 |          0  | 5 | 1 |
    +---+---+             +---+---+
 1  | 3 | 7 |          1  | 6 | 2 |
    +---+---+    or       +---+---+
 2  | 2 | 6 |          2  | 7 | 3 |
    +---+---+             +---+---+
 3  | 1 | 5 |          3  | 8 | 4 |
    +---+---+             +---+---+



    reality:

      0   1
    +---+---+
 0  | 1 | 5 |
    +---+---+
 1  | 2 | 6 |
    +---+---+
 2  | 3 | 7 |
    +---+---+
 3  | 4 | 8 |
    +---+---+
</code>

Thus we need to copy the data to the new matrix in the reverse order along one axis.

In order to allow for a two-way rotation I've introduced a numeric argument to the Piece#rotate method, defining which way (clockwise or counter-clockwise) the piece will be rotated:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rotate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(direction) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        result[i][t] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> direction </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure[t][</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i] </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure[</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t][i]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The other interesting algorithm is collision detection. This is slightly more complex than just checking boundariesof a figure. Since we can not think of a regular (circle, rectangle, line) shape for the field formed by the previous pieces, we will need to check each cell of a field against each cell of a currently falling piece. But if we decide to do that - we should either do this before rendering the falling piece (to check whether we are allowed to render it) and then, in the case of collision we will be made to "cancel" the piece's move down one cell. Alternatively, we could check each cell of a field agains the data of a falling piece, but with a one row shift down:

<code>what we draw:

+-------+
|   xx  |
|    x  |
|    x  |
|   *   |
| ****  |
| ***** |
+-------+

what we check:

+-------+
|       |
|   ..  |
|    .  |
|   *.  |
| ****  |
| ***** |
+-------+

same example,
but with the
collision occuring:

+-------+
|       |
|       |
|   ..  |
|   *.  |
| ***!  |
| ***** |
+-------+
</code>

The check is trivial: if both field cell at the checked position and any of the piece data at the piece position plus one row shift down are non-zero - then we have detected a collision and we should not move the piece down, but just render it and generate the next piece.

Improving ZSH startup performance urn:uuid:e001a9eb-84dc-57d7-9b83-89b8a0b73967 2018-06-01T00:00:00Z 2018-06-01T00:00:00Z Improving ZSH startup performance Artem Shubovych

Adding profiling to ZSH

Add this line as the first one, to the very top of your ~/.zshrc :

<code>zmodload zsh/zprof
</code>

And add this one to the very bottom of this same file:

<code>zprof
</code>

Now, whenever you open up ZSH, you shall see a list of things which start and how much time each entry takes to load. For me it was like this:

<code>num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1        1123.49  1123.49   87.59%   1123.49  1123.49   87.59%  _pyenv-from-homebrew-installed
 2)    1          84.02    84.02    6.55%     59.50    59.50    4.64%  compinit
 3)    3          26.94     8.98    2.10%     26.94     8.98    2.10%  __sdkman_export_candidate_home
 4)    3          25.77     8.59    2.01%     25.77     8.59    2.01%  __sdkman_prepend_candidate_to_path
 5)    2          24.52    12.26    1.91%     24.52    12.26    1.91%  compaudit
 6)    2           7.98     3.99    0.62%      7.98     3.99    0.62%  grep-flag-available
 7)    2           7.54     3.77    0.59%      7.54     3.77    0.59%  env_default
 8)    2           2.43     1.22    0.19%      2.43     1.22    0.19%  _has
 9)   23           2.43     0.11    0.19%      2.43     0.11    0.19%  compdef
10)    1           1.09     1.09    0.09%      1.09     1.09    0.09%  colors
11)   12           0.38     0.03    0.03%      0.38     0.03    0.03%  is_plugin
12)    1           0.38     0.38    0.03%      0.38     0.38    0.03%  is-at-least
13)    1           0.21     0.21    0.02%      0.21     0.21    0.02%  _homebrew-installed
14)    1           0.03     0.03    0.00%      0.03     0.03    0.00%  __sdkman_echo_debug

-----------------------------------------------------------------------------------
</code>

I was able to measure the total startup time by running time zsh -i -c exit . And the total startup time was almost two seconds .

<code>zsh -i -c exit  1.16s user 0.73s system 100% cpu 1.889 total
</code>

As you can see, pyenv takes whole bunch of time (1123 millis!). So I do have the pyenv plugin for ZSH and I did disable it. Here's what happened afterwards:

<code>num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1          91.42    91.42   53.38%     62.48    62.48   36.48%  compinit
 2)    2          28.94    14.47   16.90%     28.94    14.47   16.90%  compaudit
 3)    3          28.62     9.54   16.71%     28.62     9.54   16.71%  __sdkman_export_candidate_home
 4)    3          27.65     9.22   16.14%     27.65     9.22   16.14%  __sdkman_prepend_candidate_to_path
 5)    2           8.27     4.14    4.83%      8.27     4.14    4.83%  grep-flag-available
 6)    2           8.22     4.11    4.80%      8.22     4.11    4.80%  env_default
 7)    2           2.55     1.28    1.49%      2.55     1.28    1.49%  _has
 8)   23           2.50     0.11    1.46%      2.50     0.11    1.46%  compdef
 9)    1           1.24     1.24    0.72%      1.24     1.24    0.72%  colors
10)    1           0.41     0.41    0.24%      0.41     0.41    0.24%  is-at-least
11)   10           0.37     0.04    0.21%      0.37     0.04    0.21%  is_plugin
12)    1           0.02     0.02    0.01%      0.02     0.02    0.01%  __sdkman_echo_debug

-----------------------------------------------------------------------------------
</code>
<code>zsh -i -c exit  0.28s user 0.23s system 96% cpu 0.526 total
</code>

NVM

Not to forget I had NVM installed with the default settings.

With it I had the startup time of 1.9 seconds:

<code>zsh -i -c exit  1.17s user 0.74s system 99% cpu 1.916 total
</code>

If you follow this simple instruction or just replace these two lines, initializing NVM in your ~/.zshrc file:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#179299;--shiki-dark:#81C8BE"> -s</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$NVM_DIR</span><span style="color:#40A02B;--shiki-dark:#A6D189">/nvm.sh"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x26;&#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> \.</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$NVM_DIR</span><span style="color:#40A02B;--shiki-dark:#A6D189">/nvm.sh"</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  # This loads nvm</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#179299;--shiki-dark:#81C8BE"> -s</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$NVM_DIR</span><span style="color:#40A02B;--shiki-dark:#A6D189">/bash_completion"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x26;&#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> \.</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$NVM_DIR</span><span style="color:#40A02B;--shiki-dark:#A6D189">/bash_completion"</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  # This loads nvm bash_completion</span></span></code>

with these lines:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -s</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$HOME</span><span style="color:#40A02B;--shiki-dark:#A6D189">/.nvm/nvm.sh"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x26;&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">$(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">type</span><span style="color:#40A02B;--shiki-dark:#A6D189"> __init_nvm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> function </span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6"> export</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NVM_DIR</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$HOME</span><span style="color:#40A02B;--shiki-dark:#A6D189">/.nvm"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -s</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$NVM_DIR</span><span style="color:#40A02B;--shiki-dark:#A6D189">/bash_completion"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x26;&#x26;</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$NVM_DIR</span><span style="color:#40A02B;--shiki-dark:#A6D189">/bash_completion"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6"> declare</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> __node_commands</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'nvm'</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'node'</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'npm'</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'yarn'</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'gulp'</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'grunt'</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'webpack'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __init_nvm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">   for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">${__node_commands</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#179299;--shiki-dark:#81C8BE">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic"> unalias</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> done</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">   .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$NVM_DIR</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/nvm.sh</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">   unset</span><span style="color:#40A02B;--shiki-dark:#A6D189"> __node_commands</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">   unset</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -f</span><span style="color:#40A02B;--shiki-dark:#A6D189"> __init_nvm</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6"> for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">${__node_commands</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#179299;--shiki-dark:#81C8BE">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic"> alias</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $i</span><span style="color:#40A02B;--shiki-dark:#A6D189">='__init_nvm &#x26;&#x26; '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> done</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">fi</span></span></code>

The start-up time drops by 0.1 second. But it still is an improvement, right?

Software Engineering 101: how computer works urn:uuid:fbd0057a-31f0-5f2c-9d6a-353eacf090e1 2018-01-15T00:00:00Z 2018-01-15T00:00:00Z

There is some bit of information about computers which I was never told in school or at the university. This writing is trying to cover these bits in details for those interested out there.

Processor's guts

In essence, processor consists of these main blocks:

  • instruction decoder , which decodes the operation code (see below) and tells processor what it should do next
  • ALU (arithmetical-logic unit) - the device, which performs all the operations a processor is capable of - arithmetic (addition, subtraction, multiplication) and logical (bitwise OR, AND, XOR, NOT; comparing numbers)
  • registers are the places, where processor takes the input data for each operation and stores the results of each operations
  • data bus - the place, which passes data to or from memory (RAM, peripheral devices and other types of memory)
  • address bus passes memory addresses between processor and memory (to be read from or written to)

To best illustrate our examples, consider this much simplified processor model:

It has only three registers, ALU and data/address buses. I will explain all the examples below in reference to this processor.

Workflow

Processor works discretely , meaning it executes commands at certain points in time (as opposed to continuous work, where something works all the time) . Those points in time are marked by clock signals (or simply, clocks) . Processor is connected to (or has an internal one) clock signal generator , which regularly tells processor to operate. Operation is nothing but a change of the internal processor' state.

So how does processor knows what to do next? On the first clock signal, CPU loads the command with the help of instruction decoder. On the next clock tick, processor starts executing an instruction (or a command) - it either copies data to / from registers or RAM, or involves ALU. On the next clock, processor increases the command counter by one and hence proceeds to the next instruction from the pool.

In reality, this mechanism is somewhat more complex and involves more steps to just even read the command from the pool. And the pool itself is a unit on a processor chip as well and acts as another register. But to explain the processor operation, I've simplified that.

Read more to where I explain how a program in Assembly language is transformed to ones and zeroes; show a sample processor instruction set and how a program in C could be compiled to that instruction set.

Artem Shubovych

There is some bit of information about computers which I was never told in school or at the university. This writing is trying to cover these bits in details for those interested out there.

Processor's guts

In essence, processor consists of these main blocks:

  • instruction decoder , which decodes the operation code (see below) and tells processor what it should do next
  • ALU (arithmetical-logic unit) - the device, which performs all the operations a processor is capable of - arithmetic (addition, subtraction, multiplication) and logical (bitwise OR, AND, XOR, NOT; comparing numbers)
  • registers are the places, where processor takes the input data for each operation and stores the results of each operations
  • data bus - the place, which passes data to or from memory (RAM, peripheral devices and other types of memory)
  • address bus passes memory addresses between processor and memory (to be read from or written to)

To best illustrate our examples, consider this much simplified processor model:

It has only three registers, ALU and data/address buses. I will explain all the examples below in reference to this processor.

Workflow

Processor works discretely , meaning it executes commands at certain points in time (as opposed to continuous work, where something works all the time) . Those points in time are marked by clock signals (or simply, clocks) . Processor is connected to (or has an internal one) clock signal generator , which regularly tells processor to operate. Operation is nothing but a change of the internal processor' state.

So how does processor knows what to do next? On the first clock signal, CPU loads the command with the help of instruction decoder. On the next clock tick, processor starts executing an instruction (or a command) - it either copies data to / from registers or RAM, or involves ALU. On the next clock, processor increases the command counter by one and hence proceeds to the next instruction from the pool.

In reality, this mechanism is somewhat more complex and involves more steps to just even read the command from the pool. And the pool itself is a unit on a processor chip as well and acts as another register. But to explain the processor operation, I've simplified that.

Read more to where I explain how a program in Assembly language is transformed to ones and zeroes; show a sample processor instruction set and how a program in C could be compiled to that instruction set.

Assembly language

Each processor instruction is a chain of ones and zeros. Assume we have these commands processor can understand:

  • adding the values in registers A and B and storing the sum in register C and the information about possible register overflow in register S (this occurs when we do not have enough memory in register to store the result: say we have only 4 bits in each register, then what will the sum of 1111 and 1 ? 10000 , which takes 5 bits - more than we have in a register; we can then set the result to 10000 - 1111 == 0001 and proclaim "we have come over the size of register")
  • subtract the values in registers A and B and handling overflows the same way as in addition (imagine subtracting 0001 - 0001 with only 4-bit-wide registers)
  • multiply registers A and B
  • divide registers A and B (A / B)
  • perform bitwise operations AND, OR, NOT and XOR on registers A and B and store the value in register C
  • set the value of a register (either A or B) to a specific constant value
  • move a value from register C to either register A or register B
  • load data from memory under the address specified to a specific register (A or B)
  • save data from register A or B to a memory under the address specified
  • compare the values in registers A and B and set the corresponding flag in register C (whether the values are equal or A > B or B > A)
  • go to a specific instruction of a program
  • go to a specific instruction of a program, based on comparison flags in register C

Let us name these commands:

  1. ADD = A + B -> C
  2. SUB = A - B -> C
  3. MUL = A * B -> C
  4. DIV = A / B -> C
  5. NOTA = NOT A
  6. NOTB = NOT B
  7. AND = A AND B -> C
  8. OR = A OR B -> C
  9. XOR = A XOR B -> C
  10. SHR = A >> B -> C (bitwise shift right)
  11. SHL = A << B -> C (bitwise shift left)
  12. MOV A, const = const -> A
  13. MOV B, const = const -> B
  14. MOV C, A = C -> A
  15. MOV C, B = C -> B
  16. MOV A, C = A -> C
  17. MOV B, C = B -> C
  18. LOAD addr, A = memory[addr] -> A
  19. LOAD addr, B = memory[addr] -> B
  20. LOADB = memory[A] -> B
  21. SAVEB = B -> memory[A]
  22. CMP = A <=> B -> C
  23. JMP line = GOTO line
  24. JL line = if A < B (from comparison flags in C) then GOTO line
  25. JLE line = if A <= B then GOTO line
  26. JEQ line = if A == B then GOTO line
  27. JNEQ line = if A != B then GOTO line
  28. JGE line = if A >= B then GOTO line
  29. JG line = if A > B then GOTO line
  30. NOP = do nothing

This is a great subset of Assembly language commands! Just think about it: you can actually represent pretty much any program using only these 30 instructions! All the modern processors' instructions are mostly optimized variations of the commands listed above.

You can notice each command has its own number. We have fit all our commands in 25 numbers, which is great - in order to represent them in binary number we will only need 5 bits of data ( 2^5 == 32; 32 > 30 ). Now, commands have at maximum one argument. Let's say it could be at maximum 8-bit number (both addresses and lines are numbers; and since processor can only operate numbers - constants are also only numbers; when you need to represent a number as a character or vice versa - just use its ASCII code). Hence we can define an operation code format:

  1. fixed-width number of 8 bits, containing instruction number
  2. optional 8-bit argument

Assembly language is not invented separatedly from processor design, so assume all the integrated units and transistors inside our processor are aligned in a way so that when a processor receives our operation code - all of its components begin to operate immediately, according to the operation logic. In other words, processor is designed in a way which allows it to "understand" operation and its argument and set the results of its execution straight in place, when it arrives at processor's inputs.

Now let us describe the process of a program execution. The program will calculate the sum of some memory cells and store the result in a memory address:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

We now will represent this program in our simple Assembly language dialect. But first we need to design a few conventions, function call conventions. Our processor has a very limited number of registers, but is capable of operating a very big amount of RAM memory. This amount is actually determined by three factors:

  1. the size of an address bus, which determines the maximum memory address which can be represented using ones and zeros (and thus transferred to a processor via wires)
  2. the size of a data bus, which determines the maximum amount of data which can be sent to processor
  3. the capability of ALU, which determins the maximum amount of data which ALU can take in and give out

So if the address bus has the size of 8 bits, processor is only capable of addressing 2^8 == 256 memory cells. But if both data bus and ALU are capable of transporting and operating 32 bits of data - then the amount of data we are able to process is 256 cells of 32 bit == 256 * 32 == 8192 bits == 8 MB .

Back to our function call convention, we need to determine how function arguments will be passed in and how the results will be passed out. The better question is not "how" but rather "where" - we have either three registers or memory cells to choose from. Thus we can either pass up to two arguments to a function or act more clever - assume the program' memory starts at 0 and has the following format:

  • 0 - the number of program arguments
  • 0x0000 + ((n + 1) * 8) - the n-th argument

Then we need to determine how many arguments a function can take in and where to store the result of a function. Let us limit the amount of memory dedicated to function arguments to 10. Then we can determine the address of a function result: 0x0000 + ((10 + 1) * 8) == 0x0000 + 88 == 0x0058 . Everything beyond this address is treated as a program internal memory (used for storing intermediate data, variables, etc.).

In order to define the GOTO operator better and not worry about line numbers we shall use labels (but only during composing programs - assume compiler will substitute them with the actual line number values). Labels will be used like this: LABEL_NAME: &#x3C;instruction> .

It would also be nice to be able to comment out some code. To comment the line (and thus do not take it into account when processing) we will use the semicolon symbol: ; comment .

Now that we have everything we need to componse a full program we can finally translate our sum function in C to our Assembly dialect:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; program bootstrap:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; these 3 steps are done by the callee (operating system or other function)</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; - load the number of arguments, 2, to memory[0x0000]</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; - load the address `*a` to memory[0x0008]</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; - load the value of `n` to memory[0x00F0]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; assumptions:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; - i &#x3C;=> memory[0x0058 + 8] == memory[0x0060]</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; - result &#x3C;=> memory[0x0058] == memory[0x0058] - we can just use the defined-by-convention memory cell in-place</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0060</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; A = &#x26;i</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0000</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; B = 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SAVEB                </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; move B -> memory[A] &#x3C;=> i = 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0058</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; A = &#x26;result</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0000</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; B = 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SAVEB                </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; move B -> memory[A] &#x3C;=> result = 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">LOOP</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: LOAD A, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0060</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; i -> A</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LOAD B, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x00F0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">       ; n -> B</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">CMP</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                  ; A &#x3C;=> B => C</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">JGE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> RETURN           </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; if i >= n then GOTO RETURN</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LOAD B, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0060</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">       ; B = i</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0004</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; A = 4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MUL</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                  ; C = A * B &#x3C;=> C = i * 4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C, A             </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; A = C &#x3C;=> A = i * 4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0004</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; B = *a (the beginning of array `a`)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">ADD</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                  ; C = A + B &#x3C;=> C = &#x26;a + i * 4 == a[i]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C, A             </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; A = a[i]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LOAD B, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0058</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">       ; B = memory[0x0058] &#x3C;=> B = result</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">ADD</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                  ; C = A + B &#x3C;=> C = result + a[i]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C, B             </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; B = C</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0058</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; A = &#x26;result</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SAVEB                </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; memory[0x0058] = B &#x3C;=> result = B &#x3C;=> result == result + a[i]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LOAD </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0060</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, B       </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; B = i</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0001</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; A = 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">ADD</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                  ; C = A + B &#x3C;=> C = i + 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> C, B             </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; B = C &#x3C;=> B = i + 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x0060</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        ; A = &#x26;i</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SAVEB                </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; memory[0x0060] = B &#x3C;=> i = B &#x3C;=> i = i + 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">JMP</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> LOOP</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">             ; GOTO LOOP</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">RETURN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOP</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">          ; program shutdown:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                     ; store the `result` value in memory[0x0058] - we operate on `result` through this address already, nothing to do here</span></span></code>

For processor to run this code it needs to be compiled to opcodes first. For example, the MOV A, 0x0060 instruction will be converted (according to our convention) as:

<code>0000 1100    0110 0000
~~~~~~~~~    ~~~~~~~~~
    ^            ^
    |            |
    |    0x0060 -┘
    |
    └- MOV A, const
</code>

To quickly recap, here is our processor instruction list together with its opcodes:

No. Instruction Operation code
1 ADD 0000 0001 0000 0000
2 SUB 0000 0010 0000 0000
3 MUL 0000 0011 0000 0000
4 DIV 0000 0100 0000 0000
5 NOT A 0000 0101 0000 0000
6 NOT B 0000 0110 0000 0000
7 AND 0000 0111 0000 0000
8 OR 0000 1000 0000 0000
9 XOR 0000 1001 0000 0000
10 SHR 0000 1010 0000 0000
11 SHL 0000 1011 0000 0000
12 MOV A, const 0000 1100 xxxx xxxx
13 MOV B, const 0000 1101 xxxx xxxx
14 MOV C, A 0000 1110 0000 0000
15 MOV C, B 0000 1111 0000 0000
16 MOV A, C 0001 0000 0000 0000
17 MOV B, C 0001 0001 0000 0000
18 LOAD A, addr 0001 0010 xxxx xxxx
19 LOAD B, addr 0001 0011 xxxx xxxx
20 LOADB 0001 0100 0000 0000
21 SAVEB 0001 0101 0000 0000
22 CMP 0001 0110 0000 0000
23 JMP line 0001 0111 xxxx xxxx
24 JLE line 0001 1000 xxxx xxxx
25 JL line 0001 1001 xxxx xxxx
26 JEQ line 0001 1010 xxxx xxxx
27 JNEQ line 0001 1011 xxxx xxxx
28 JGE line 0001 1100 xxxx xxxx
29 JG line 0001 1101 xxxx xxxx
30 NOP 0001 1110 0000 0000

We will also need to extract only effective lines from our code and number each line (in order to operate with JMP-like instructions). And then all we need to do - is to substitute the commands in the source code with the ones from a table above and replace all those xxxx xxxx values (which stand for 8 bits of instruction' argument):

Line no. Code Instruction code Argument Argument (binary) Instruction + argument
0 MOV A, 0x0060 0000 1100 xxxx xxxx 96 0110 0000 0000 1100 0110 0000
1 MOV B, 0x0000 0000 1101 xxxx xxxx 0 0000 0000 0000 1101 0000 0000
2 SAVEB 0001 0101 0000 0000 0001 0101 0000 0000
3 MOV A, 0x0058 0000 1100 xxxx xxxx 88 0101 1000 0000 1100 0101 1000
4 MOV B, 0x0000 0000 1101 xxxx xxxx 0 0000 0000 0000 1101 0000 0000
5 SAVEB 0001 0101 0000 0000 0001 0101 0000 0000
6 LOOP: LOAD A, 0x0060 0001 0010 xxxx xxxx 96 0110 0000 0001 0010 0110 0000
7 LOAD B, 0x00F0 0001 0011 xxxx xxxx 240 1111 0000 0001 0011 1111 0000
8 CMP 0001 0110 0000 0000 0001 0110 0000 0000
9 JGE RETURN 0001 1100 xxxx xxxx 29 0001 1101 0001 1100 0001 1101
10 LOAD B, 0x0060 0001 0011 xxxx xxxx 96 0110 0000 0001 0011 0110 0000
11 MOV A, 0x0004 0000 1100 xxxx xxxx 4 0000 0100 0000 1100 0000 0100
12 MUL 0000 0011 0000 0000 0000 0011 0000 0000
13 MOV C, A 0000 1110 0000 0000 0000 1110 0000 0000
14 MOV B, 0x0004 0000 1101 xxxx xxxx 4 0000 0100 0000 1101 0000 0100
15 ADD 0000 0001 0000 0000 0000 0001 0000 0000
16 MOV C, A 0000 1110 0000 0000 0000 1110 0000 0000
17 LOAD B, 0x0058 0001 0011 xxxx xxxx 88 0101 1000 0001 0011 0101 1000
18 ADD 0000 0001 0000 0000 0000 0001 0000 0000
19 MOV C, B 0000 1111 0000 0000 0000 1111 0000 0000
20 MOV A, 0x0058 0000 1100 xxxx xxxx 88 0101 1000 0000 1100 0101 1000
21 SAVEB 0001 0101 0000 0000 0001 0101 0000 0000
22 LOAD B, 0x0060 0001 0011 xxxx xxxx 96 0110 0000 0001 0011 0110 0000
23 MOV A, 0x0001 0000 1100 xxxx xxxx 1 0000 0001 0000 1100 0000 0001
24 ADD 0000 0001 0000 0000 0000 0001 0000 0000
25 MOV C, B 0000 1111 0000 0000 0000 1111 0000 0000
26 MOV A, 0x0060 0000 1100 xxxx xxxx 96 0110 0000 0000 1100 0110 0000
27 SAVEB 0001 0101 0000 0000 0001 0101 0000 0000
28 JMP LOOP 0001 0111 xxxx xxxx 6 0000 0110 0001 0111 0000 0110
29 RETURN: NOP 0001 1110 0000 0000 0001 1110 0000 0000

We have just did the same job a compiler does for us when we write code in a high-level language like C. You can see the code is verbose, what is caused by us and the limitations / conventions we have agreed on. But we can extend either the assembly language by adding new instructions, which will simplify writing programs or by extending the processor architecture by introducing stack and increasing the power of ALU etc. For instance, we could have changed the moving data between memory and registers and thus reduce the amount of both registers needed to do that and the amount of commands needed for the operation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> A, addr</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B, value</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SAVEB</span></span></code>

could become

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">MOV</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> B, [addr]</span></span></code>

Or we could have agreed on opcode size and skip the 8 bits of data for instructions without arguments and thus reduce the size of compiled programs.

Processing programs

What happens when we run a program on our PC? There is a little bit of magic which must happen first. You run a program (most of the time) from an operating system. And this operating system needs to perform some actions before it can send your program's commands straight to a processor - reserve some memory, make scheduling... And since most operating systems are meant to be multi-tasked (allow multiple programs to run simultaneously), OS can not allow your program to just send all of its commands to a processor, one by one - if your program is faulty then any other program might have never been executed again, even the OS itself! That's why operating system decides when to send the next command to a processor to execute it. This also allows for optimizations on multi-core and multi-processor systems - when two operations could be executed simultaneously, whithout overwriting memory used by another one - it can be run on a different core or processor to speed up the execution.

That's why our program will not contain programmer-defined commands only. Let's have a look at the standard Windows executable file (PE32) structure:

You can see it has lots of headers , which describe different aspects of a program and two major sections - text (containing the code itself) and data (containing all the constant definitions and allocations). Each executable can also contain resources like images, sounds and others - if needed.

We all know how to write a program in, say, C. But how a program in C (or any other language) is "understood" (and thus, executed) by a processor? One may have heard of Assembly language. This is a low-level programming language (in opposite to C, which is a high-level programming language). "Low-level" means that a programmer writes instructions for the processor in the order processor will pick them up and execute, one by one, exactly as they are set in a program, ommiting syntactic sugar constructions like loops, if-then-else operators and so on. Usually in such programming languages programmers operate memory addresses and numbers only. On the other hand, high-level programs, containing all the syntactic sugar features, are first translated to something processor can "understand" and execute - processors commands (instructions). The program is also being in terms of removing unused and unreacheable code, replacing expressions which can be pre-calculated into the results of pre-calculation (like the expression x * 2 * 32 could be simply written as x * 64 or x &#x3C;&#x3C; 4 , which most of the compilers will do by default because of performance reasons - binary shift operation is way more faster than multiplication; but for programmer it might be required to stay explicit in order to highlight some calculations or just to stay clear for other programmers).

Let us have a look at how programs are compiled. Consider this program in C:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> product</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

It will be compiled into this assembly code:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">product(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">):</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # @product(int, int)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  imul</span><span style="color:#D20F39;--shiki-dark:#E78284"> edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">esi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">edi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  ret</span></span></code>

Looks simple, huh?

In essence, each line of a program in assembly language looks like this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">label</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> command operand1, operand2</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # comment</span></span></code>

Both label, operands and comment are optional with the exception that operands requirements depend on command.

Operands could be either numbers, registers (refer to processor registers) or memory addresses.

Registers represent cells in processor memory, those are very limited in number and size, but are directly accessed by processor and thus are very, very fast. There are eight general-purpose registers, common for majority of processors: AX, BX, CX, DX, SP, BP, SI, DI. There are other registers, but we will cover them later. Each command will store its result in one of these registers. These registers have size of one word (2 bytes, 16 bits). Each register has "lower byte" and, correspondingly, "higher byte" - for AX they are AL (low) and AH (high), representing first and last 8 bits of a register. These registers are available for all 16-bit processors. More modern 32-bit processors have extended versions of each register, for AX it is EAX, for CX its ECX and so on. They are twice as big as their non-extended versions (32 bit, 2 words). Nowadays 64-bit systems have extended versions of extended registers, having 4 words and precended with letter R: RAX, RBX and so on. There are also 16 registers worth 128 bit each, XMM0 .. XMM15.

Addressing memory refers to the computer's RAM; in order to operate with RAM processor first copies the data from RAM to its registers and then performs operation on data in registers. Processor is unable to operate with RAM data directly. You can see clearly such operations require additional actions from processor, namely - copy data from RAM to registers before executing operation and copy the data back to RAM after the operation execution (usually this step is stated separatedly by a programmer). This is time-consuming. And since RAM is not that fast as processor's registers, it makes operations slow. Memory is addressed using one of these syntaxes:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[address] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; [0x12345]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[register] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; [RAX] - takes address, contained in register RAX</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[register + number] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; [RAX + 2]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[register + register * number] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; [RAX + RBX * 3]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[register + register * number + number] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; [RBX + EAX * 4 + 3]</span></span></code>

You can also do more tricky thing: define a named constant - give a literal name to a number and then refer to a value by its name. But first you need to reserve a memory for it:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">constant_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> db</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0x123</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; define one byte value (0x123) and give it a name "constant_name"</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">constant2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> dw</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 'ab' </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; define one word (two bytes) of values 0x61 and 0x62, correspondingly</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">const3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> dd</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 'abcd' </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; define double-word (four bytes)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">const4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> dq</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0x123456789abcdef0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; 8-byte wide constant</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">const5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> dq</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.234567e20</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; double-precision constant</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">const6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> dt</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.234567e20</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; extended-precision constant</span></span></code>

Note I'm constantly mentioning numbers, but never characters or strings. That's because eventually all this data is just a number (character code or a pointer to a memory - effectively, an address of a memory). And processor can only operate on numbers, nothing else. Compiler will convert all these characters and floating-point values to hexadecimal integer values anyway.

You can also reserve a bunch of memory cells using res command:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">const1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> resb</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; reserve 2 bytes</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">const2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> resw</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; reserve 16 words</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">const3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> resq</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; reserve seven 8-byte cells</span></span></code>

This way each constant will point to the first of the reserved array' cells in RAM.

Let's take a look at our example again:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> product</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Its assembly code is:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">product(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">):</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # @product(int, int)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  imul</span><span style="color:#D20F39;--shiki-dark:#E78284"> edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">esi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">edi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  ret</span></span></code>

This program has exactly three effective lines:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">imul</span><span style="color:#D20F39;--shiki-dark:#E78284"> edi</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">esi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; multiply the data in two registers, EDI and ESI and store the result of multiplication in EAX register</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">edi</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; copy the data from EAX to EDI</span></span></code>
<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">ret</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; restore pointer to the currently running command and the values in registers from stack</span></span></code>

See, assembly is still a somewhat high-level language - one command does a little bit of "magic" like storing the result somewhere, or restoring the processor state ( ret ) or storing its state and moving to the different command or sub-routing or function ( call ). Each processor has its own set of commands, which might be more optimized for this particular processor. That's why it is really hard to get each program run best on all possible computers when distributing it. But the "basic set" of commands is quite common for majority of processors and you can be quite confident about them.

So after the program is written in Assembly (which is the lowest reasonable language we can more or less easily write code in) it is compiled into... something... Binary code is what you might have been thinking of. And you are totally correct - programs are essentially just a set of ones and zeros. But more interesting question is how a computer executes them?

If we compile our function into binary file - we will get each Assembly command translated into a long hexadecimal (or binary - if you split a long list of ones and zeros into chunks of 16 digits - you will be able to write them down as one character, which is much more compach, right?) value, describing the opcode of a command and its arguments. Each Assembly command has its own code, just like character in a string. And each register has its own code too. Combine them - and you will get a long number. Convert it to binary - and you will get a line of machine codes.

Processor then reads the operation code and acts exactly as it says - if it would be imul RAX, RBX - processor will do just exactly as it says - multiply the value in register RAX by the value in register RBX and then save the result in register RAX . To explain how processor actually multiplies values from registers and stores them - we need to go one level lower - and get familiar with how processor does that on the electonics level. But we won't do that. Instead, we will just scratch the surface by describing how fast those operations could be.

You might have heard about processor's frequency or clock rate . This is a number, showing how frequently an electronic impulse is sent over all the processor's schematic to enforce its state update. Effectively, what it means is each processor operation like multiplication, addition, subtraction, moving the data around and others, need to change the state of different electronic components, mainly - triggers and transistors. When talking about addition of two registers, for example, processor will need to calculate the sum of each bit pair in registers given, handling overflows, different register lengths and clearing the state of the resutl register beforehand. Some processors are designed to do that in one cycle, but mainly addition will be done in several clocks . Hence a processor with a clock rate of 1 GHz will not make 1 billion additions, subtractions, multiplications or other operations per second. For a reference, here is a diagram, showing how many clocks does each operation takes in average

Remember I have mentioned optimization a while ago? Here's a sample table of how many clocks do some processor instructions take (in average):

With this knowledge we can easily talk about more high-level things.

Based on How stuff works

IntelliJ productivity tips urn:uuid:dbda50da-4d46-5870-89bf-aefc8ed236f7 2017-09-18T00:00:00Z 2017-09-18T00:00:00Z

This post is based on a talk on IntelliJ productivity and contains some tips and tricks I found handy in my everyday work.

You may disagree with me or find these recommendations useless for yourself, but I and some of my teammates have found out these tips have made us more efficient when dealing with lots of code in a big project.

  • say "no!" to tabs -- that's it -- disable them. Forever. IntellJ has many ways to navigate the project, just check them out: Cmd+E , Cmd+Alt+← and Cmd+Alt+→

  • stop using mouse -- just as with navigation in open files, IntelliJ offers awesome code navigation: want to go to the method definition? Cmd+B , want to find a file or class or method? Shift, Shift or Ctrl+Shift+N or Ctrl+N , want to move around in Project Manager? Cmd+1 (and then Esc to switch between editor and Manager)

  • use IntelliJ's code intelligence -- if you forgot what params method takes, use Cmp+P , if you want to find variable or class or method usage -- use Alt+F7 , use the power of "Refactor -> Extract Constant/Field" function

  • use action finder popup -- that one can save you lot of time when you do not remember where the function needed is located or what key shortcut to use -- Cmd+Shift+A is your friend

WARNING: lots of video/gifs under the cut!

Artem Shubovych

This post is based on a talk on IntelliJ productivity and contains some tips and tricks I found handy in my everyday work.

You may disagree with me or find these recommendations useless for yourself, but I and some of my teammates have found out these tips have made us more efficient when dealing with lots of code in a big project.

  • say "no!" to tabs -- that's it -- disable them. Forever. IntellJ has many ways to navigate the project, just check them out: Cmd+E , Cmd+Alt+← and Cmd+Alt+→

  • stop using mouse -- just as with navigation in open files, IntelliJ offers awesome code navigation: want to go to the method definition? Cmd+B , want to find a file or class or method? Shift, Shift or Ctrl+Shift+N or Ctrl+N , want to move around in Project Manager? Cmd+1 (and then Esc to switch between editor and Manager)

  • use IntelliJ's code intelligence -- if you forgot what params method takes, use Cmp+P , if you want to find variable or class or method usage -- use Alt+F7 , use the power of "Refactor -> Extract Constant/Field" function

  • use action finder popup -- that one can save you lot of time when you do not remember where the function needed is located or what key shortcut to use -- Cmd+Shift+A is your friend

WARNING: lots of video/gifs under the cut!

Summary

Open/hide tool window (Project, Structure, Version Control, etc.)
<code>&#x3C;div>&#x3C;kbd>Cmd+1&#x3C;/kbd> .. &#x3C;kbd>Cmd+9&#x3C;/kbd>&#x3C;/div>

&#x3C;div>
    To go back to editor - just hit &#x3C;kbd>Esc&#x3C;/kbd> &#x3C;br />
    Project Tree: &#x3C;br />
    &#x3C;video preload autoplay loop muted>
        &#x3C;source src="/images/intellij-performance-tips/cmd_1_esc.webm" />
        &#x3C;source src="/images/intellij-performance-tips/cmd_1_esc.webp" />
    &#x3C;/video>
    &#x3C;br />
    Search results:
    &#x3C;br />
    &#x3C;video preload autoplay loop muted>
        &#x3C;source src="/images/intellij-performance-tips/cmd_3_esc.webm" />
        &#x3C;source src="/images/intellij-performance-tips/cmd_3_esc.webp" />
    &#x3C;/video>
    &#x3C;br />
    Version Control:
    &#x3C;br />
    &#x3C;video preload autoplay loop muted>
        &#x3C;source src="/images/intellij-performance-tips/cmd_9_esc.webm" />
        &#x3C;source src="/images/intellij-performance-tips/cmd_9_esc.webp" />
    &#x3C;/video>
&#x3C;/div>
</code>
Switch between open files
Cmd+E
Go back/forward
Cmd+Alt+← and Cmd+Alt+→
Search for class, method, variable
Shift, Shift
One-night games: Tetris urn:uuid:dcd6c0e8-5d50-5c3a-8783-7e38938a2f72 2017-09-10T00:00:00Z 2017-09-10T00:00:00Z

Did you ever think of how old games like tetris or snake (hail the Nokia fans!) work?

I always wanted to write a few relatively simple games just to practice my coding skills. Back when I was at the uni, I've made peg solitaire and three-in-a-row games in C/C++ with SFML. I even wrote a (pretty shitty) server-client chess game (be warned: this code was written in 2011 and only contains fixes to make it run on a new version of SFML, so it might look... smelly... on each and every line...) . My latest achievements were the Entanglement game and a well-designed (at least from my perspective) arcade space shooter .

But I've never implemented more well-known games like tetris or snake. And they are interesting from the algorithmic perspective.

And recently I've came to the point when I really wanted to create something interesting. And that was the chance to try myself as a early-2000-ies developer!

As I wanted to accomplish my goal as soon as possible, I've decided to not pick up any libraries and just implement everything with HTML5 Canvas API. And this is what I ended up with:

In this post I'll talk about Tetris. Under the cut you'll find the interesting algorithmic solutions I've used for it.

Artem Shubovych

Did you ever think of how old games like tetris or snake (hail the Nokia fans!) work?

I always wanted to write a few relatively simple games just to practice my coding skills. Back when I was at the uni, I've made peg solitaire and three-in-a-row games in C/C++ with SFML. I even wrote a (pretty shitty) server-client chess game (be warned: this code was written in 2011 and only contains fixes to make it run on a new version of SFML, so it might look... smelly... on each and every line...) . My latest achievements were the Entanglement game and a well-designed (at least from my perspective) arcade space shooter .

But I've never implemented more well-known games like tetris or snake. And they are interesting from the algorithmic perspective.

And recently I've came to the point when I really wanted to create something interesting. And that was the chance to try myself as a early-2000-ies developer!

As I wanted to accomplish my goal as soon as possible, I've decided to not pick up any libraries and just implement everything with HTML5 Canvas API. And this is what I ended up with:

In this post I'll talk about Tetris. Under the cut you'll find the interesting algorithmic solutions I've used for it.

Tetris

Source code

The most interesting part about tetris was to implement piece rotation. I've represented all the possible figures as a list of matrices.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> FIGURES </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The problem however is that all figures are different, hence all the matrices have different dimensions - a "stick" is 4x1, whilst a "cube" is 2x2. Other pieces are 3x2. Rotation algorithm might not be simple. And it implies one limitation - pieces should preserve their position - not to move to the sides when rotating them.

Pieces are best represented as matrices, but in order to operate on matrices we need to have the corresponding methods. I decided to just implement the class Piece with the essential methods:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Piece</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> col</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">piece </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">slice</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">apply</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(shape)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">col </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> col</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">row </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Here row and col describe the position of a piece on a screen whilst rows and cols are the dimensions of a piece. piece contains the matrix data of a piece.

The rotation algorithm I've implemented tries to transpose piece's matrix in a very simple manner:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Piece</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    rotate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Array</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result[i]) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                result[i] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                result[i][t] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure[t][</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

What it does is actually creating a totally new matrix, where the dimensions are swapped and the data is the opposite data to what was in the original matrix. In other words, we iterate the original matrix over its normal indices, but write the data to the new matrix in the reversed direction. So if we read the row with index 0 and column with index 2 , this means we need to write the data from the source matrix at data[0][2] to the destination matrix at data[2][0] . Sounds correct, right?

But if we do that with the array, we will end up having the new matrix mirrored:

<code>           given:

      0   1   2   3
    +---+---+---+---+
 0  | 1 | 2 | 3 | 4 |
    +---+---+-------+
 1  | 5 | 6 | 7 | 8 |
    +---+---+---+---+


            expectation:

      0   1                0    1
    +---+---+             +---+---+
 0  | 4 | 8 |          0  | 5 | 1 |
    +---+---+             +---+---+
 1  | 3 | 7 |          1  | 6 | 2 |
    +---+---+    or       +---+---+
 2  | 2 | 6 |          2  | 7 | 3 |
    +---+---+             +---+---+
 3  | 1 | 5 |          3  | 8 | 4 |
    +---+---+             +---+---+



    reality:

      0   1
    +---+---+
 0  | 1 | 5 |
    +---+---+
 1  | 2 | 6 |
    +---+---+
 2  | 3 | 7 |
    +---+---+
 3  | 4 | 8 |
    +---+---+
</code>

Thus we need to copy the data to the new matrix in the reverse order along one axis.

In order to allow for a two-way rotation I've introduced a numeric argument to the Piece#rotate method, defining which way (clockwise or counter-clockwise) the piece will be rotated:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rotate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(direction) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        result[i][t] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> direction </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure[t][</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cols </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i] </span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">figure[</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rows </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t][i]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The other interesting algorithm is collision detection. This is slightly more complex than just checking boundariesof a figure. Since we can not think of a regular (circle, rectangle, line) shape for the field formed by the previous pieces, we will need to check each cell of a field against each cell of a currently falling piece. But if we decide to do that - we should either do this before rendering the falling piece (to check whether we are allowed to render it) and then, in the case of collision we will be made to "cancel" the piece's move down one cell. Alternatively, we could check each cell of a field agains the data of a falling piece, but with a one row shift down:

<code>what we draw:

+-------+
|   xx  |
|    x  |
|    x  |
|   *   |
| ****  |
| ***** |
+-------+

what we check:

+-------+
|       |
|   ..  |
|    .  |
|   *.  |
| ****  |
| ***** |
+-------+

same example,
but with the
collision occuring:

+-------+
|       |
|       |
|   ..  |
|   *.  |
| ***!  |
| ***** |
+-------+
</code>

The check is trivial: if both field cell at the checked position and any of the piece data at the piece position plus one row shift down are non-zero - then we have detected a collision and we should not move the piece down, but just render it and generate the next piece.

Floyd-Warshall algorithm urn:uuid:adce6e1a-b74f-5ac2-bd12-ebf59fec7152 2017-08-16T00:00:00Z 2017-08-16T00:00:00Z

Update

There is a revised version of this blog , showing how an algorithm implementation could be optimized.

The story behind this post

Recently I've received 10 karma on StackOverflow. I was curious for what question or answer and clicked to check this. It appeared to be a seven-year-old answer about a Floyd-Warshall algorithm. I was surprised with both my bad English (back those days...) and the very small value the answer had. So I've revised it and here it is -- the brand-new version!

The definitions

Let us have a graph, described by matrix D , where D[i][j] is the length of the edge (i -> j) (from graph's vertex with index i to the vertex with index j ) .

Matrix D has the size of N * N , where N is a total number of vertices in a graph because we can reach the maximum of paths by connecting each graph's vertex to each other.

Also, we'll need matrix R , where we will store the vertices of the shortest paths ( R[i][j] contains the index of a vertex, where the shortest path from vertex i to vertex j lies).

Matrix R has the same size as D .

The Floyd-Warshall algorithm performs these steps:

  1. initialize the matrix of all the paths between any two pairs of vertices in a graph with the edge's end vertex (this is important since this value will be used for path reconstruction)

  2. for each pair of connected vertices (read: for each edge (u -> v) ) , u and v , find the vertex, which forms shortest path between them: if the vertex k defines two valid edges (u -> k) and (k -> v) (if they are present in the graph) , which are together shorter than path (u -> v) , then assume the shortest path between u and v lies through k ; set the shortest pivot point in matrix R for edge (u -> v) to be the corresponding pivot point for edge (u -> k)

But how do we read the matrix D ?

Artem Shubovych

Update

There is a revised version of this blog , showing how an algorithm implementation could be optimized.

The story behind this post

Recently I've received 10 karma on StackOverflow. I was curious for what question or answer and clicked to check this. It appeared to be a seven-year-old answer about a Floyd-Warshall algorithm. I was surprised with both my bad English (back those days...) and the very small value the answer had. So I've revised it and here it is -- the brand-new version!

The definitions

Let us have a graph, described by matrix D , where D[i][j] is the length of the edge (i -> j) (from graph's vertex with index i to the vertex with index j ) .

Matrix D has the size of N * N , where N is a total number of vertices in a graph because we can reach the maximum of paths by connecting each graph's vertex to each other.

Also, we'll need matrix R , where we will store the vertices of the shortest paths ( R[i][j] contains the index of a vertex, where the shortest path from vertex i to vertex j lies).

Matrix R has the same size as D .

The Floyd-Warshall algorithm performs these steps:

  1. initialize the matrix of all the paths between any two pairs of vertices in a graph with the edge's end vertex (this is important since this value will be used for path reconstruction)

  2. for each pair of connected vertices (read: for each edge (u -> v) ) , u and v , find the vertex, which forms shortest path between them: if the vertex k defines two valid edges (u -> k) and (k -> v) (if they are present in the graph) , which are together shorter than path (u -> v) , then assume the shortest path between u and v lies through k ; set the shortest pivot point in matrix R for edge (u -> v) to be the corresponding pivot point for edge (u -> k)

But how do we read the matrix D ?

Inputs

Take sample graph:

In GraphViz it would be described as follows:

<code class="language-dot">digraph G {
    layout = "circo";

    0->2 [label = "1"];
    2->3 [label = "5"];
    3->1 [label = "2"];
    1->2 [label = "6"];
    1->0 [label = "7"];
}
</code>

We first create a two-dimensional array of size 4 (since there are exactly 4 vertices in our graph) .

We initialize its main diagonal (the items, whose indices are equal, for ex. G[0, 0] , G[1, 1] , etc.) with zeros, because the shortest path from vertex to itself has the length 0 and the other elements with a very large number (to indicate there is no edge or an infinitely long edge between them) . The defined elements, corresponding to graph's edges, we fill with edges' lengths:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[,]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9999</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And let's say we initialize our D matrix by hand:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The algorithm itself

Now that we are on a same page with definitions, algorithm can be implemented like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[,]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> R </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// Initialise the routes matrix R, essentially saying "the shortest path from u to v is straight"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// Floyd-Warshall algorithm; note the order of iterators DOES matter:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // check if the shortest path from "u" to "v" is actually through "k"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Let's "animate" this algorithm in few steps for the sample graph from above:

Initial state

  • the D matrix contains distance from vertex u to vertex v , where both u and v are indexes of those vertices in a graph and u is the index of a row and v is the index of the column in any of the matrices R and D
  • path from u to u is thought to be infinitely long meaning we do not allow this type of paths
  • in matrix R we define the shortest path from u to v to lie through v
D
0 1 2 3
0 0 1
1 7 0 6
2 0 5
3 2 0
R
0 1 2 3
0 0 1 2 3
1 0 1 2 3
2 0 1 2 3
3 0 1 2 3

Step 1

We try to find the vertex which makes the shorter path through itself than the direct path between two vertices. E.g. for every vertex k we find the pair of vertices u and v where path u -> v is longer than the path u -> k -> v . If we found one - we will update the matrices D and R , correspondingly.

For vertex k = 0 we will check each combination of:

paths through 0 starting at 0 :

  • 0 -> 0 vs 0 -> 0 -> 0
  • 0 -> 1 vs 0 -> 0 -> 1
  • 0 -> 2 vs 0 -> 0 -> 2
  • 0 -> 3 vs 0 -> 0 -> 3

paths through 0 starting at 1 :

  • 1 -> 0 vs 1 -> 0 -> 0
  • 1 -> 1 vs 1 -> 0 -> 1
  • 1 -> 2 vs 1 -> 0 -> 2
  • 1 -> 3 vs 1 -> 0 -> 3

paths through 0 starting at 2 :

  • 2 -> 0 vs 2 -> 0 -> 0
  • 2 -> 1 vs 2 -> 0 -> 1
  • 2 -> 2 vs 2 -> 0 -> 2
  • 2 -> 3 vs 2 -> 0 -> 3

paths through 0 starting at 3 :

  • 3 -> 0 vs 3 -> 0 -> 0
  • 3 -> 1 vs 3 -> 0 -> 1
  • 3 -> 2 vs 3 -> 0 -> 2
  • 3 -> 3 vs 3 -> 0 -> 3

As you can see, there are lots of invalid paths here - those which either do not exist or do not make sense. Examples are: paths which do not exist (like 0 -> 3 ) and paths to any vertex through source vertex (like 0 -> 0 -> 0 and 0 -> 0 -> (any) ) .

We could easily reduce the amount of the steps performed by the algorithm by throwing few if conditions to check for those cases.

But let's first finish animating this step: there are very few valid paths amongst N * N === 16 of those we've checked. And only one comparison: for path 1 -> 2 vs 1 -> 0 -> 2 we compare 6 (direct) and 7 + 1 = 8 ( 1 -> 0 and then 0 -> 2 ) .

So there are no changes in our matrices.

D
0 1 2 3
0 0 1
1 7 0 6
2 0 5
3 2 0
R
0 1 2 3
0 0 1 2 3
1 0 1 2 3
2 0 1 2 3
3 0 1 2 3

Step 2

For vertex 1 we will check each combination of:

paths through 1 starting at 0 :

  • 0 -> 0 vs 0 -> 1 -> 0
  • 0 -> 1 vs 0 -> 1 -> 1
  • 0 -> 2 vs 0 -> 1 -> 2
  • 0 -> 3 vs 0 -> 1 -> 3

paths through 1 starting at 1 :

  • 1 -> 0 vs 1 -> 1 -> 0
  • 1 -> 1 vs 1 -> 1 -> 1
  • 1 -> 2 vs 1 -> 1 -> 2
  • 1 -> 3 vs 1 -> 1 -> 3

paths through 1 starting at 2 :

  • 2 -> 0 vs 2 -> 1 -> 0
  • 2 -> 1 vs 2 -> 1 -> 1
  • 2 -> 2 vs 2 -> 1 -> 2
  • 2 -> 3 vs 2 -> 1 -> 3

paths through 1 starting at 3 :

  • 3 -> 0 vs 3 -> 1 -> 0
  • 3 -> 1 vs 3 -> 1 -> 1
  • 3 -> 2 vs 3 -> 1 -> 2
  • 3 -> 3 vs 3 -> 1 -> 3

This case is more interesting - there are more things to compare. Let's see each combination:

  1. 3 -> 0 does not exist ( inf )
  2. 3 -> 1 has length 2 and 1 -> 0 has length 7 , the indirect path 3 -> 1 -> 0 has length 9

Hence we will update matrices D and R reflecting that.

For path 3 -> 1 -> 2 :

  1. there is no path from 3 to 2 directly, so its length is inf
  2. 3 -> 1 has length 2 and 1 -> 2 has length 6 , the total is 8 which is infinitely better than infinity

Here are the updated matrices:

D
0 1 2 3
0 0 1
1 7 0 6
2 0 5
3 9 2 8 0
R
0 1 2 3
0 0 1 2 3
1 0 1 2 3
2 0 1 2 3
3 1 1 1 3

Step 3

For vertex 2 we will check each combination of:

paths through 2 starting at 0 :

  • 0 -> 0 vs 0 -> 2 -> 0
  • 0 -> 1 vs 0 -> 2 -> 1
  • 0 -> 2 vs 0 -> 2 -> 2
  • 0 -> 3 vs 0 -> 2 -> 3

paths through 2 starting at 1 :

  • 1 -> 0 vs 1 -> 2 -> 0
  • 1 -> 1 vs 1 -> 2 -> 1
  • 1 -> 2 vs 1 -> 2 -> 2
  • 1 -> 3 vs 1 -> 2 -> 3

paths through 2 starting at 2 :

  • 2 -> 0 vs 2 -> 2 -> 0
  • 2 -> 1 vs 2 -> 2 -> 1
  • 2 -> 2 vs 2 -> 2 -> 2
  • 2 -> 3 vs 2 -> 2 -> 3

paths through 2 starting at 3 :

  • 3 -> 0 vs 3 -> 2 -> 0
  • 3 -> 1 vs 3 -> 2 -> 1
  • 3 -> 2 vs 3 -> 2 -> 2
  • 3 -> 3 vs 3 -> 2 -> 3

The valid comparisons are:

  • 0 -> 3 vs 0 -> 2 -> 3
  • 1 -> 3 vs 1 -> 2 -> 3

In first case, we compare infinity ( 0 -> 3 ) to 1 + 5 == 6 ( 0 -> 2 and then 2 -> 3 ). In second case we compare infinity again ( 1 -> 3 ) to 6 + 5 == 11 ( 1 -> 2 and then 2 -> 3 ). In both cases we select the path through vertex 2 .

D
0 1 2 3
0 0 1 6
1 7 0 6 11
2 0 5
3 9 2 8 0
R
0 1 2 3
0 0 1 2 2
1 0 1 2 2
2 0 1 2 3
3 1 1 1 3

Step 4

For vertex 3 we will check each combination of:

paths through 3 starting at 0 :

  • 0 -> 0 vs 0 -> 3 -> 0
  • 0 -> 1 vs 0 -> 3 -> 1
  • 0 -> 2 vs 0 -> 3 -> 2
  • 0 -> 3 vs 0 -> 3 -> 3

paths through 3 starting at 1 :

  • 1 -> 0 vs 1 -> 3 -> 0
  • 1 -> 1 vs 1 -> 3 -> 1
  • 1 -> 2 vs 1 -> 3 -> 2
  • 1 -> 3 vs 1 -> 3 -> 3

paths through 3 starting at 2 :

  • 2 -> 0 vs 2 -> 3 -> 0
  • 2 -> 1 vs 2 -> 3 -> 1
  • 2 -> 2 vs 2 -> 3 -> 2
  • 2 -> 3 vs 2 -> 3 -> 3

paths through 3 starting at 3 :

  • 3 -> 0 vs 3 -> 3 -> 0
  • 3 -> 1 vs 3 -> 3 -> 1
  • 3 -> 2 vs 3 -> 3 -> 2
  • 3 -> 3 vs 3 -> 3 -> 3

This case is the last one. It is similar to the previous two. But please note that we are using the matrix values from the previous step.

For path 0 -> 1 :

  1. direct path from 0 to 1 does not exist, take it as inf
  2. shortest path from 0 to 3 (whichever it is) has length 6 ; 3 -> 1 has length 2 ; the total path has length 8 which is better than infinity

For path 2 -> 0 :

  1. direct path 2 -> 0 does not exist
  2. the edge 2 -> 3 exists and has length 5 ; path from 3 to 0 has length 9 ; so the shortest path from 2 to 0 through 3 will have length 9 + 5 == 14

For path 2 -> 1 :

  1. there is no direct path 2 -> 1
  2. the path 2 -> 3 is 5 and 3 -> 1 is 2 , so 2 -> 3 -> 1 is 7

Both matrices R and D will be updated to reflect that:

D
0 1 2 3
0 0 8 1 6
1 7 0 6 11
2 14 7 0 5
3 9 2 8 0
R
0 1 2 3
0 0 2 2 2
1 0 1 2 2
2 3 3 2 3
3 1 1 1 3

And then the algorithm is done.

Path reconstruction

In order to reconstruct the path from vertex u to vertex v , you need follow the elements of matrix R , effectively going "through" each vertex:

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int32</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Path </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int32</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        start </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Let's follow this logic in steps again, "animating" the algorithm. For instance, the longest path in this graph possible, from 0 to 1 :

  1. start = 0, end = 1
  2. R[0, 1] == 2, start = 2, end = 1
  3. R[2, 1] == 3, start = 3, end = 1
  4. R[3, 1] == 1, start = 1, end = 1

So the path from 0 to 1 is all the values the start variable takes (except last) , namely: 0 -> 2 -> 3 .

Summary

The whole code could be wrapped in a couple of methods:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> System</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Collections</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Generic</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> FloydWarshallPathFinder</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[,]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[,]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FloydWarshallPathFinder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NumberOfVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[,]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> EdgesLengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        N </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NumberOfVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        D </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> EdgesLengths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        R </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[,]</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FindAllPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        R </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int32</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FindShortestPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">R </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            FindAllPaths</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">        List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int32</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Path </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> List</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int32</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            start </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> R</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Path</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MainClass</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[,]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9999</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">        FloydWarshallPathFinder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathFinder </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> FloydWarshallPathFinder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">N</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        Console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">WriteLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Path: {0}"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> String</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">" -> "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathFinder</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">FindShortestPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ToArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

You can read 'bout this algorithm on wikipedia and get some data structures generated automatically here

Easy way to understand algorithm complexity and big O notation urn:uuid:8c24b51b-1218-5c62-afae-41580b3ada62 2017-08-15T00:00:00Z 2017-08-15T00:00:00Z

Foreword

Some time ago I've published an article about bit O notation . I've mentioned its source but never published it. So here it is, the original article.

The article

Big O notation is the most widely used method which describes algorithm complexity - the execution time required or the space used in memory or in the disk by an algorithm. Often in exams or interviews, you will be asked some questions about algorithm complexity in the following form:

For an algorithm that uses a data structure of size n, what is the run-time complexity or space complexity of the algorithm? The answer to such questions often uses big O notations to describe the algorithm complexity, such as O(1) , O(n) , O(n^2) or O(log(n)) .

Artem Shubovych

Foreword

Some time ago I've published an article about bit O notation . I've mentioned its source but never published it. So here it is, the original article.

The article

Big O notation is the most widely used method which describes algorithm complexity - the execution time required or the space used in memory or in the disk by an algorithm. Often in exams or interviews, you will be asked some questions about algorithm complexity in the following form:

For an algorithm that uses a data structure of size n, what is the run-time complexity or space complexity of the algorithm? The answer to such questions often uses big O notations to describe the algorithm complexity, such as O(1) , O(n) , O(n^2) or O(log(n)) .

Big O for time complexity

Here we don't want to discuss big O mathematically. Basically, when analyzing the time complexity of an algorithm, big O notation is used to describe the rough estimate of the number of "steps" to complete the algorithm. Let's take the following example:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fun</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // partl</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    doSomething</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // part2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        doSomething</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // part3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            doSomething</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // part4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Here lets assume that doSomething() takes C steps to complete. The whole fun(n) method has 4 parts. What is the time complexity of each part for different parameters n ?

For part 1, it does doSomething() so it takes constant C steps. Here C is independent of the parameter n . When the time complexity is independent of the parameter, we use O(1) to mark it.

For part 2, it does doSomething() exactly n times. Each time it takes C steps. So in total, it takes C*n steps to complete part 2. Then as described above, we use O(1) to complete the C steps. Then for C*n , the complexity becomes n * O(1) . Here, an important rule is that a * O(n) equals O(a * n) . In such case, n * O(1) = O(n) . So the time complexity of part 2 is O(n) .

For part 3, it has two loops. The inner loop is exactly like part 2. The outer loop does part 2 n times again so the time complexity of part 3 is n * O(n) which is O(n^2) .

For part 4, it takes exactly 1 step to return. So the time complexity is O(1) .

Then what is the total time complexity of the whole fun(n) ? It is easy, we just need to add up the time complexity of all the 4 parts:

<code>O(1) + O(n) + O(n^2) + O(1)
</code>

Now let's assume n becomes very-very large. Parts 1 and 4 will still take constant number of steps, C + 1 , to complete, so the total time of running part 1 and part 4 could be ignored when calculating the execution time for part 2 and part 3, as now both part 2 and part 3 take much more time than part 1 and part 4.

Let's we compare part 2 and part 3:

  • when n is 1 , both part 2 and part 3 take C steps
  • when n is 3 , part 2 takes 3*C steps while part 3 takes 9*C steps
  • when n is 1000 , part 2 needs 1000 * C steps but part 3 takes 1000000 * C steps!

As n increases, the time complexity of part 3 increases much quicker than part 2. When n becomes extremely large, the time of part 2 can be ignored by the time of part 3.

So here is another rule: when we add up big O notation, the notation with slower increase speed could be ignored by the notation with faster increase speed. As we could see, O(1) does not increase at all so it could be ignored by O(n) . O(n) is slower than O(n^2) so it could be ignored by O(n^2) . Therefore, the complexity of the whole fun() is O(n^2) .

Rules summary of big O notation

From the above examples, we could summarize the following rule: for multiplying two O notations, O(A) and O(B) , the result is O(A*B) . For example:

<code>O(1) x O(n) = O(n).
O(n) x O(n) = O(n^2).
O(1) + O(n) = O(n).
O(n) + O(n^2) = O(n^2).
O(1) + O(n) + O(n^2) = O(n^2).
</code>

Here is the comparison of the increase speed of different O notations:

<code>O(1) &#x3C; O(log(n)) &#x3C; O(n) &#x3C; O(n * log(n)) &#x3C; O(n^2)
</code>

How to use big O notation to compare algorithm complexity and why

When comparing different algorithms, we often say the one with a "smaller" big O notation is more efficient. However, there are situations that algorithms with "smaller" bit O is faster.

For example, there are two algorithms f1(n) and f2(n) . f(1) takes 100 steps and f(2) takes n steps so f(1) is O(1) and f(2) is O(n) . When n is less than 100 , f1(n) is more efficient than f2(n) . However, big O compares when n goes to extremely (or infinitely) large. When n goes up to 10000 , f2(n) becomes way more efficient. As the nature of large-scale data in computer engineering, it makes more sense to compare algorithms in the cases that the data is very large.

Big 0 for space complexity

It is easier to understand using big O to estimate space complexity as it is more concrete. For example, in an algorithm, we need to create an array of size n to store the temporary results before getting the final result. If we assume that the size of the element in the array is a constant C which is independent of n , the space complexity of using the array is C*n which is

<code>O(n) x O(C) = O(n) x O(1) = O(n)
</code>

When comparing different algorithms, we often compare how much "extra" space complexity is needed to solve the problem. For example, as an algorithm that needs an extra array of size n is not as good as the one which only needs two variables, O(1) space complexity is more efficient than O(n) .

Gantt chart with D3 urn:uuid:e2c70c91-6987-5570-b116-3efa466bcca1 2017-04-09T00:00:00Z 2017-04-09T00:00:00Z

Contents

At work, I've had a task to implement a Gantt chart diagram to show dependencies and order of some... let's say, milestones. Given this feature is in a very unstable beta in Google Charts, I thought to myself: "Why don't I implement it on my own?" . And tried to recall my D3 knowledge.

I've also found a minimalistic, but helpful example / screenshot of some Gantt chart implementation:

The challenges I've faced were:

  1. order milestones on a timeline
  2. scale milestones to fit in a viewport
  3. create pretty connection lines
  4. center text inside each milestone

And since D3 is a data-driven library, I've used map/reduce where possible.

Here's how the result looked like:

The implementation details are under the cut.

Update August 2020

There are few updates to this original implementation in my new blog .

Artem Shubovych

Contents

At work, I've had a task to implement a Gantt chart diagram to show dependencies and order of some... let's say, milestones. Given this feature is in a very unstable beta in Google Charts, I thought to myself: "Why don't I implement it on my own?" . And tried to recall my D3 knowledge.

I've also found a minimalistic, but helpful example / screenshot of some Gantt chart implementation:

The challenges I've faced were:

  1. order milestones on a timeline
  2. scale milestones to fit in a viewport
  3. create pretty connection lines
  4. center text inside each milestone

And since D3 is a data-driven library, I've used map/reduce where possible.

Here's how the result looked like:

The implementation details are under the cut.

Update August 2020

There are few updates to this original implementation in my new blog .

I hope the implementation is more or less clear, but here are some details: the algorithm consists of three main parts - initial data pre-processing - (parsing and validating dates, calculating the default values and so on); calculating the graphics params (positions, sizes) and finally, rendering that into SVG.

I've tried using caches whenever possible to optimize the performance and save some calculation time by just creating maps id -> object , since the algorithm refers to objects by their IDs a lot (like getting all the children of an element or getting a particular child's data).

The data pre-processing is basically computing the length of each element based on either startDate and endDate or startDate and duration . Adding the endDate and duration option is possible and trivial, but I thought this is a less useful feature.

The transformation of data is the most interesting part - we need to calculate the positions of each element on a "screen", and it heavily relies on data sorting mode - if we need to sort the data by the amount of children - this is somewhat simple. But if we sort data by dates - we need to count for element's index in the overall list of elements.

Then we calculate the parameters of connection lines. They might be redundant for some users, but in my case it was essential to show the dependencies between elements sorted by children count. This is less trivial, since one needs to find the bends of each line. Hence I decided to simplify this problem by putting all the lines under the rectangles and assuming every line consists of these sections:

  1. the "input" and "output" pins (near the endDate end of a parent element and near startDate end of children element)
  2. two vertical sections to reach the height of a children element
  3. a connection between the lines from p. 2

The last piece of an algorithm is generating SVG. This is where D3 strikes in and, given all the params generated in the previous section, creates SVG elements in DOM tree and scales them considering svgOptions passed to the main function.

The implementation is below and the live demo is here

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#D20F39;--shiki-dark:#E78284"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d3 </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'd3'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moment </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'moment'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> prepareDataElement</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> label</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> startDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> endDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> duration</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dependsOn</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startDate </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endDate) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">duration) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    throw</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Error</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Wrong element format: should contain either startDate and duration, or endDate and duration or startDate and endDate'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (startDate) startDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(startDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (endDate) endDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(endDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (startDate </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endDate </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> duration) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    endDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(startDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(duration[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> duration[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startDate </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> endDate </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> duration) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    startDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(endDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    startDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">subtract</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(duration[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> duration[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dependsOn)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dependsOn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    label</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    startDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    endDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    duration</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dependsOn</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> findDateBoundaries</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStartDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxEndDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> startDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> endDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">minStartDate </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> startDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isBefore</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(minStartDate)) minStartDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(startDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">minStartDate </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isBefore</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(minStartDate)) minStartDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(endDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxEndDate </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isAfter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(maxEndDate)) maxEndDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(endDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxEndDate </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> startDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isAfter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(maxEndDate)) maxEndDate </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(startDate)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    minStartDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    maxEndDate</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createDataCacheById</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">cache</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> elt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cache</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [elt</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elt </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createChildrenCache</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dataCache </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createDataCacheById</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fillDependenciesForElement</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">eltId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dependenciesByParent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dataCache[eltId]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dependsOn</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">parentId</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dependenciesByParent[parentId])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        dependenciesByParent[parentId] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (dependenciesByParent[parentId]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">indexOf</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(eltId) </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        dependenciesByParent[parentId]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">push</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(eltId)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      fillDependenciesForElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(parentId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dependenciesByParent)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">cache</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> elt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cache[elt</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      cache[elt</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id] </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    fillDependenciesForElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(elt</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cache)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cache</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sortElementsByChildrenCount</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> childrenByParentId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createChildrenCache</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sort</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> e2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (childrenByParentId[e1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id] </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> childrenByParentId[e2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id] </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> childrenByParentId[e1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> childrenByParentId[e2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id]</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sortElementsByEndDate</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sort</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">e1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> e2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endDate)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isBefore</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">moment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(e2</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endDate)))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sortElements</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> sortMode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (sortMode </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'childrenCount'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sortElementsByChildrenCount</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (sortMode </span><span style="color:#179299;--shiki-dark:#81C8BE">===</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'date'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sortElementsByEndDate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseUserData</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(prepareDataElement)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createPolylineData</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">rectangleData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> elementHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // prepare dependencies polyline data</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cachedData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createDataCacheById</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(rectangleData)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // used to calculate offsets between elements later</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> storedConnections </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rectangleData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reduce</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> e</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [e</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id]</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // create data describing connections' lines</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rectangleData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flatMap</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dependsOn</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">parentId</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cachedData[parentId])</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">parent</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> color </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#'</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">min</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">random</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())) </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0xFFF</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toString</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // increase the amount rows occupied by both parent and current element (d)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        storedConnections[parent</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id]</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        storedConnections[d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id]</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaParentConnections </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> storedConnections[parent</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id] </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaChildConnections </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> storedConnections[d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id] </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> points </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaChildConnections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaChildConnections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.25</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          parent</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xEnd </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaParentConnections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.25</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          parent</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xEnd </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deltaParentConnections</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (parent</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          parent</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">xEnd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (parent</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          points</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> points</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">','</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">          color</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createElementData</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> elementHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> xScale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> fontSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> xScale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">startDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toDate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xEnd </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> xScale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toDate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> width </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xEnd </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> height </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> charWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (width </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fontSize)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dependsOn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dependsOn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tooltip </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">label</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> singleCharWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fontSize </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> singleCharHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fontSize </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.45</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> label </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">label</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (label</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> charWidth) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      label </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> label</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">split</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">''</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">slice</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> charWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">''</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '...'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> labelX </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((width </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((label</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> singleCharWidth))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> labelY </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((height </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (singleCharHeight))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      xEnd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      width</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      height</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      dependsOn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      label</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      labelX</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      labelY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      tooltip</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createChartSVG</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> placeholder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> svgWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> svgHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> elementHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scaleWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> fontSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> minStartDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> maxEndDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> margin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> showRelations</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // create container element for the whole chart</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svg </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d3</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(placeholder)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'svg'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgWidth)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'height'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgHeight)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xScale </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d3</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">scaleTime</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">domain</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([minStartDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toDate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxEndDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toDate</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()])</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">range</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleWidth])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // prepare data for every data element</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> rectangleData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createElementData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xScale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fontSize)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xAxis </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d3</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">axisBottom</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(xScale)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // create container for the data</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svg</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'transform'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `translate(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // add milestone relationship lines to the SVG</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (showRelations) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // create data describing connections' lines</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> polylineData </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createPolylineData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(rectangleData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> linesContainer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'transform'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `translate(0,</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    linesContainer</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">selectAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'polyline'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">data</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(polylineData)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'polyline'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'fill'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'none'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">color)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'points'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">points)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // append milestones only after we have rendered the connections to prevent lines overlapping the milestones</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> barsContainer </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> g1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'transform'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `translate(0,</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">top</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  g1</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(xAxis)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // create axes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> bars </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> barsContainer</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">selectAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">data</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(rectangleData)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">enter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'g'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  bars</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rect'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'rx'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ry'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'y'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'width'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">width)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'height'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">height)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'fill'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '#ddd'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'stroke'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'black'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  bars</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'text'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'fill'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'black'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'font-family'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'sans-serif'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">labelX)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">attr</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'y'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">labelY)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">label)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  bars</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'title'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">text</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tooltip)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">export</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createGanttChart</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">placeholder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> elementHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> sortMode</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'date'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> showRelations</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> svgOptions</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // prepare data</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> margin </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (svgOptions </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgOptions</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">margin) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    top</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    left</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ((svgOptions </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgOptions</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">width) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 600</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Math</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">max</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">((svgOptions </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgOptions</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">height) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 200</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">top </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleWidth </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">left </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleHeight </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (margin</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">top </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fontSize </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (svgOptions </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgOptions</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fontSize) </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> parseUserData</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // transform raw user data to valid values</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sortElements</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sortMode)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStartDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxEndDate </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> findDateBoundaries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // add some padding to axes</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  minStartDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">subtract</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'days'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  maxEndDate</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'days'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  createChartSVG</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> placeholder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> svgHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elementHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleHeight</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fontSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> minStartDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxEndDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> margin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> showRelations </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

The data format is like follows

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    startDate</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '2017-02-27'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '2017-03-04'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    label</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'milestone 01'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'm01'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dependsOn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> []</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    startDate</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '2017-02-23'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '2017-03-01'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    label</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'milestone 06'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'm06'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dependsOn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'m01'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    duration</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'days'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '2017-03-24'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    label</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'milestone 02'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'm02'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dependsOn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'m04'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    startDate</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '2017-02-27'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    duration</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'days'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    label</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'milestone 03'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'm03'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dependsOn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'m01'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    endDate</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '2017-03-17'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    duration</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'days'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    label</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'milestone 04'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'm04'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dependsOn</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'m01'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

To create a chard on a page, you need to pass the reference to a valid existing DOM element where you want the diagram to appear, the data and the SVG options. These options define the looks of a chart - width, height of an element (rectangle), font size and so on. One more option is

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createGanttChart</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'body'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  elementHeight</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  sortMode</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'date'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // alternatively, 'childrenCount'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  svgOptions</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1200</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    height</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 400</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    fontSize</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

A lot of things are happening here. In short, here are few key points:

  • we have to render entities (milestones, lines, labels) in a specific "layered" order, to prevent one set of things covering the other
  • it is both good for performance and is kind of a requirement to calculate the data before rendering it
Entanglement urn:uuid:02f7a389-8921-5a6b-8d1c-8fb98ed8fd9a 2017-03-13T00:00:00Z 2017-03-13T00:00:00Z

Entanglement?

Some time ago there was a game popular over there, called Entanglement:

There are a few implementations of this game under Android:

But there was no such game for iOS. And as I pursued my second M. Sc. degree, I have had a course "iOS development", where we were learning to use Swift and iOS platform.

I decided to implement this game as my course project. In Swift. Originally the game was implemented in Swift 2 (there was no Swift 3 back those days) .

And recently I decided to refactor the game a bit and update it to the most recent Swift version (which is Swift 3 at the moment of writing this post) .

In this post I'll describe some interesting decisions I made while creating this game.

Artem Shubovych

Entanglement?

Some time ago there was a game popular over there, called Entanglement:

There are a few implementations of this game under Android:

But there was no such game for iOS. And as I pursued my second M. Sc. degree, I have had a course "iOS development", where we were learning to use Swift and iOS platform.

I decided to implement this game as my course project. In Swift. Originally the game was implemented in Swift 2 (there was no Swift 3 back those days) .

And recently I decided to refactor the game a bit and update it to the most recent Swift version (which is Swift 3 at the moment of writing this post) .

In this post I'll describe some interesting decisions I made while creating this game.

The game

The idea of the game is to prolong the line as much as possible by using the tiles with pieces of a path for a line. At the beginning of the game, a single tile is placed at the center of a hexagonal field and the line starts from that tile. You are also given a tile in the "pocket", which you can swap with the currently active one. At each turn, a game will place a new tile at the end of the line and you have three actions available:

  1. rotate the current tile clockwise or counter-clockwise, as many times as you want
  2. swap the current tile with one in the pocket; you can repeat this action as many times as you want to
  3. place the tile; this action is performed once and can not be undone

But the trick here is: each tile contains six line pieces. And by using one of them, be aware that other pieces might be used later as well.

When you place a tile, you get one point for the first piece of the line, which prolongs it. You also get one point more for the next piece, if it prolongs the line too. For the third line piece, you'll get 3 points and so on. The point here is: the more pieces you connect in a single move - the more points you get.

Implementation

My implementation contains several core elements:

  1. tiles
  2. field
  3. tile renderer
  4. game itself

Tiles contain information on the line pieces they contain and provide methods to rotate themselves and find connections with neighbor tiles.

The field contains information on all the tiles on the field - where they are placed and how they are rotated.

Tile renderer simply draws tiles into an image. Doing so allows having an animation for tile rotation.

The game holds all the data on the game state - tile in the pocket, currently selected tile, line path done so far and a score.

Field

The core of the game is tiles. The tiles are hexagons. And the whole field is hexagonal. The problem was to handle the positions of all the tiles in a handy manner. Thus I decided to go from a standard Cartesian coordinate system, which has 90° angle between axes and go for a one with 120°:

Here, u and v vectors represent coordinate axes and w vector is a diagonal. So the tiles could now be allocated so their centers are at the points of the coordinate system with integer coordinates:

Now, there's a tricky thing regarding this coordinate system: how should we know, where to render the actual tile image on a screen? E. g. how can we convert coordinates in this system back to Cartesian?

After doing some math on a piece of paper, I came up with this function:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> uv2xy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> uv</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv.0, v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> uv.1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kx </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ky </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sqrt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">kx </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tileSideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ky </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tileSideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cx </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tileSideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cy </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sqrt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tileSideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cx </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x, cy </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

What happens here is: since every tile is a regular hexagon, we can simply calculate the distance between the sides of neighbour tiles and, based on how the tiles are layed out relative to each other, multiply that by either taking one and a half of every coordinate system unit or sqrt(3) / 2 of one unit. The sqrt(3) / 2 comes from the length of a unit regular hexagon's height (a line, perpendicular to any side of a hexagon, starting at its center) . Every unit scales with the tile' size.

As you can see, it depends on tile side length. This is the major tile parameter. Since I render tiles based on that parameter.

Tiles

Each tile should have six lines. To do that, I created 12 "connection slots" , two on each side of a tile, as shown below:

Then, by generating six random pairs of integer numbers from the range [1, 12] , we can obtain actual connections inside a single tile. Note that none of the numbers should be used more than once and that none of the pairs should have a duplicate. Then a tile might look like this:

To display a tile, I've developed a prototype tile in SVG:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">svg</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> height</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"232"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> width</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"232"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">polygon</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> points</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"55.0,5.0 155.0,5.0 205.0,92.0 155.0,178.0 55.0,178.0 5.0,92.0"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"fill:none;stroke:#000;stroke-width:2"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">svg</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

And to make this template re-usable, I've dropped in a "side length" parameter. Pre-calculating pins' slots positions and hexagon's vertex positions and making it parametric (with a side length parameter) , I've got this function, which generates a tile:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TileImageGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertices: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">50</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">150</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">200</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">87</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">150</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">173</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">50</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">173</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">87</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> width: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> height: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleCoefficient: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> centerX: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> centerY: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    init</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sideLength</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.sideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100.0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.width </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.sideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.height </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.73</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.sideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.centerX </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.width </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.centerY </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.height </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> borderTile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIImage </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> size </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">width</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.width, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">height</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.height</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> opaque </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale: CGFloat </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        UIGraphicsBeginImageContextWithOptions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">size, opaque, scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> context </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> UIGraphicsGetCurrentContext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // draw outer shape</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shapePathRef: CGMutablePath </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGMutablePath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFillColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UIColor.black.cgColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setLineJoin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CGLineJoin.round</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices.count </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                shapePathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">move</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x0, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            shapePathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x1, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shapePathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">closeSubpath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shapePathRef</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fillPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // finish drawing</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> image </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> UIGraphicsGetImageFromCurrentImageContext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        UIGraphicsEndImageContext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> image</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now, if I want to draw connection lines, I can just spicy that code with pre-calculated pin slots connections coordinates and, using some neat line stroke technique, draw tile exactly as shown above:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RenderingParams</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sideLength: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stroke: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathStroke: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strokeColor: UIColor</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathColor: UIColor</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> highlightPathColor: UIColor</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> markPathColor: UIColor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    init</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sideLength</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        stroke</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        pathStroke</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        strokeColor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: UIColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> UIColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">red</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">green</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">alpha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        pathColor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: UIColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIColor.white,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        highlightPathColor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: UIColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> UIColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">red</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">green</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">alpha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        markPathColor</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: UIColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> UIColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">red</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.9</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">green</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">alpha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            self.sideLength </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sideLength</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            self.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> stroke</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            self.pathStroke </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathStroke</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            self.strokeColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> strokeColor</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            self.pathColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathColor</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            self.highlightPathColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> highlightPathColor</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            self.markPathColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> markPathColor</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TileImageGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vertices: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">50</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">150</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">200</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">87</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">150</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">173</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">50</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">173</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">87</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pins: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">83</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">116</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">166</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">29</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">182</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">58</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">182</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">116</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">166</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">145</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">116</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">173</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">83</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">173</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">34</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">145</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">18</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">116</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">18</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">58</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">34</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">29</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> width: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> height: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scaleCoefficient: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> centerX: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> centerY: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderingParams: RenderingParams</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    init</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">renderingParams</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: RenderingParams</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.renderingParams </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> renderingParams</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.sideLength</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100.0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.width </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.0</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.sideLength </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.height </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">ceil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1.73</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.sideLength </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.centerX </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.width </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.centerY </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.height </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> nonEmptyTile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tileParams</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: TileParams</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIImage </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> size </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGSize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">width</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.width, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">height</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.height</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> opaque </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale: CGFloat </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        UIGraphicsBeginImageContextWithOptions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">size, opaque, scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> context </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> UIGraphicsGetCurrentContext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // draw outer shape</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shapePathRef: CGMutablePath </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGMutablePath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFillColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">UIColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">red</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.88</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">green</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.88</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.88</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">alpha</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.cgColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setLineJoin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CGLineJoin.round</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices.count </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y0 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                shapePathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">move</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x0, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            shapePathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addLine</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x1, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shapePathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">closeSubpath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shapePathRef</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fillPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // draw connections</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c0, c1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tileParams.connections </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setLineWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.pathStroke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> connectionPathRef: CGMutablePath </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGMutablePath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pathColor: CGColor</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tileParams.mark.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">contains</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$0.0 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c0 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $0.1 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$0.0 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c1 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $0.1 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                pathColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.markPathColor.cgColor</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tileParams.highlight.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">contains</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">where</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$0.0 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c0 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $0.1 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ||</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$0.0 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c1 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $0.1 </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> })</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                pathColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.renderingParams.highlightPathColor.cgColor</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                pathColor </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.renderingParams.pathColor.cgColor</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p0x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.pins</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p0y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.pins</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p1x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.pins</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p1y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.pins</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.scaleCoefficient </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            connectionPathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">move</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p0x, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p0y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            connectionPathRef.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addQuadCurve</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p1x, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p1y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">control</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> CGPoint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.centerX, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.centerY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setLineWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.pathStroke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setStrokeColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UIColor.black.cgColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">connectionPathRef</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">strokePath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setLineWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.pathStroke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setStrokeColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pathColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">connectionPathRef</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">strokePath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // stroke out the outer shape to cover the paths</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setStrokeColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.strokeColor.cgColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setLineWidth</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">CGFloat</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">self.renderingParams.stroke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addPath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shapePathRef</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        context</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">strokePath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // finish drawing</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> image </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> UIGraphicsGetImageFromCurrentImageContext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        UIGraphicsEndImageContext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> image</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

As you can see, two major things happened here:

  1. I encapsulated all the parameters like line stroke width and line colors ina a separate class, RenderingParams
  2. I added rendering lines using two-time rendering technique to emulate borders over connection lines; e. g. I first draw a thick line, filled with the stroke color, which should be applied, and then I render a thinner line with exactly the same coordinates, but different color; doing so, the bottom line becomes just a background for the top one

Now, tiles should be rotated. To do that, two tricks have been applied:

  1. as we have our tiles drawn as UIImage , we can simply rotate that image around its center to create the visual effect of rotation
  2. as we have our connection pins as a plain array, we can just re-calculate the indices of connection's "input" and "output"

There are a couple of points, which should be described prior to the algorithm of a tile rotation.

The tiles are connected using those connection pins. And based on the coordinates of a tile and its neighbor, we can tell, which pins of those two will be connected. And since our game goal is to prolong a single line, by keeping track of which connections of which tiles form a line, we may define a couple rules:

  • given connected pins inside one tile, we may describe that connection in two pins' indices, namely "input" and "output"
  • connections of a tile, not involved in forming a line, can be treated in either way - input and output could be named in a reversed order (again, unless they are forming a line , otherwise it's essential to say where the line comes from and where it ends inside a given tile)
  • the central tile will have only one output - the one, where the line starts its journey; let it be the connection pair (0, 0)
  • one can easily calculate the neighbor's output, given the last tile of a line path and its successor

Let's define a class Tile :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Tile</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> connections: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Simple enough, right? Now let's assume our program will fill out connections list automatically and all the tiles will be assigned the correct list of connections. Given that, we may define two helper methods on a Tile class:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Tile</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> connections: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> output</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> input</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">inPin, outPin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.connections </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inPin </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> outPin</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> outPin </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inPin</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> output</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">output </span><span style="color:#179299;--shiki-dark:#81C8BE">%</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">output </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">output </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The first one, output(from input: Int) will return us the output index inside a given tile, where the line will come out from, when entering our tile from input with index from .

So, for example, given a tile with connections

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t: Tile </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Tile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t.connections </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">11</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span></code>

the call t.output(from: 11) will give us 8 , which could be easily found from the list of connections by hand.

The second method will give us the input index inside the neighbor tile, which is connected to an output of the given tile.

And for the example above, the call t.input(from: 0) will give us 7 . And here's an image to show why:

Given we have a portion of a path layed out on a game plane already, there is only one way of correctly placing each next tile (the path which is already present on a plane never changes and always comes to the same connection point) .

And now it's finally the time to explain the rotation of the tiles!

After a tile has been assigned a set of connected pins, the rotation should preserve those connections. The rotation operation uses modulo operation, as with calculating neighbor tile's input pin index, but on a scale of each connection pair (a pair of input and output) :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Tile</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> rotate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> direction</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        self.connections </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.connections.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">output</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> in</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">input </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">direction </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">output </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">direction </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    //...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Here, direction is either 1 for clockwise rotation or -1 for counter-clockwise rotation.

Path prediction

Finding a place where to put the next tile is an iterative process, which hardly depends on a current tile (its connections and position) and the tiles which are already placed on the field.

At the very beginning of the game, the next place could be set as a constant and is always above the central tile (so if the central tile has the position (4, 4) , then the next place would be (5, 5) - along with the diagonal in our coordinate system) .

To track the boundaries of a field and the beginning of the line (in other words - the places, where the line cannot go) , I inherited a Tile class with a set of other classes just to track if the game can continue or not: ZeroTile and BorderTile represent restricted bounds of a game field.

Now, given the output of a current tile, which the line will use to continue through the tile, we can predict where the next tile should be put on a field:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> findNextPlace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: Path, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">currentPosition</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u, v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentPosition</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> output: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> path.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lastOutput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    switch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> output </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u, v </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">7</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">9</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">11</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u, v </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    default</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u, v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

If, however, there is a tile at the next place on the field, we should use its connections to determine the next position.

Otherwise, if the next position is either the border of a field or an empty space - we stop the search.

Search itself is just as simple as that:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">func</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> findFuturePath</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tile</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: NonEmptyTile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> throws</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Path, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isPathFinished</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        throw</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> GameError.gameOver</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpPath: Path </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpNextPlace: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.nextPlace</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    tmpPath.items </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [self.path.items.last</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u, v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpNextPlace</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lastOutput: </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Int</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpPath.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lastOutput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nextTile: Tile</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.nextPlace.0 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.nextPlace.1 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            nextTile </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tile</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            nextTile </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.tiles</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[v]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nextTile </span><span style="color:#179299;--shiki-dark:#81C8BE">is</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> NonEmptyTile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            break</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        tmpPath.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">expand</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nextTile.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">input</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lastOutput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">output</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> try</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nextTile.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">outputFromNeighbourOutput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">from</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lastOutput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        tmpNextPlace </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">findNextPlace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tmpPath, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nextPlace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpNextPlace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpNextPlace.0 </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpNextPlace.1 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            break</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u, v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmpNextPlace</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    tmpPath.items.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">removeFirst</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tmpPath, tmpNextPlace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Counting points

This task is quite simple, compared to the others described above. When a user places a tile, we estimate the length of a predicted path and add numbers from [1..L] (where L is the length of the predicted path) to score. This could be expressed as a sum of a finite arithmetic sequence with a step of 1 :

The end result

The end result of this coding exercise looks like exactly as the one at the very top of this post:

libc.js: component interaction urn:uuid:9cb5d241-9ddf-56c5-91d3-0e38df340819 2017-03-12T00:00:00Z 2017-03-12T00:00:00Z

libc.js

Recently I've written a post about functional programming techniques, coming into the world of front-end and the library I crafted as an experiment. That library, libc.js was highly inspired by Elm and Mithril . But it suffered two major features:

  1. components were hardly able to be used in other components
  2. the interaction between components was nearly impossible (or, at least, not very transparent)

What's hidden beneath the next version of the library?

Artem Shubovych

libc.js

Recently I've written a post about functional programming techniques, coming into the world of front-end and the library I crafted as an experiment. That library, libc.js was highly inspired by Elm and Mithril . But it suffered two major features:

  1. components were hardly able to be used in other components
  2. the interaction between components was nearly impossible (or, at least, not very transparent)

What's hidden beneath the next version of the library?

The next logical step in library development was to make the interaction between components smooth and natural. I was primarily thinking of two options:

  1. inheriting component from a VirtualDOMNode class
  2. passing both properties and children as arguments to the view function of a component

I'll first describe the second approach a bit: since properties and children basically describe a VirtualDOMNode itself, that meant to pass a VirtualDOMNode instance to the view function. And if I did so, I'd get Mithril.js .

If I inherit a component class from a VirtualDOMNode , I'd step away from the initial purpose of keeping view and update functions separated and pure.

The library exposes a Store class, which is very similar to Redux . This class was also used internally to handle components' state changes. But that did not solve the problem in any way.

I ended up creating a Component class, which encapsulated both view and update functions, internal component state and the dispatch function, which operated on the component's internal state. I also exposed the render() method, which could then be used to bind a component to an external Store object (which I'll cover in a minute) .

Re-using components

The changes made allowed components to be used in other components. To illustrate that, I created a Tab component and the corresponding example:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Tabs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (message</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SELECT_TAB'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Object</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">assign</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{},</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                currentTabIndex</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> message</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tabIndex</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> view</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentTabIndex </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">currentTabIndex </span><span style="color:#179299;--shiki-dark:#81C8BE">||</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tabHeaders </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> children</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">tab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tabIndex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `tab-header </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tabIndex</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentTabIndex</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'selected'</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    click</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SELECT_TAB'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                        tabIndex</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [ tab</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tabs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> children</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">tab</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tabIndex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `tab-content </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tabIndex</span><span style="color:#179299;--shiki-dark:#81C8BE"> ==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> currentTabIndex</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'selected'</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                tab</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">children</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">slice</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'tab-headers'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tabHeaders ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'tab-container'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tabs ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createComponent</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> app </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> view</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> children</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ Tabs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'header'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Tab #1'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'FIRST TAB CONTENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'header'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Tab #2'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'SECOND TAB CONTENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'header'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Tab #3'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'THIRD TAB CONTENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ] ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createComponent</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(view)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">app</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">init</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mount</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'#app'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

I also use these styles to make tabs look like tabs:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-container</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    flex-direction</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> column</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-headers</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> flex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    justify-content</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> space-around</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-header</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    text-align</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    cursor</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pointer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    flex-grow</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#179299;--shiki-dark:#81C8BE">hover</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    text-decoration</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> underline</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#179299;--shiki-dark:#81C8BE">hover</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    text-decoration</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-header</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    background</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ddd</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-content</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">tab-content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">selected</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> block</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This example shows how Tabs component could be used and, what's more important, as a High-Order Component , passing tabs along with their headers as a set of children to the Tabs component.

Using external state

Using component's render() method and the createStore(initialState) function, exposed by a library, we can also create and use the store as an external state provider for our component:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counterStore </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createStore</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (message </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INCREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (message </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DECREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">counterStore</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onAction</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(update)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    let</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> click</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'INCREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> click</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'DECREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `Count: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getState</span><span style="color:#40A02B;--shiki-dark:#A6D189">() </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Counter </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createComponent</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(view)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">counterStore</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onStateChanged</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Counter</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Counter</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">init</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counterStore </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mount</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Here you can see how to create a store with an initial state. The initial state could be pretty much anything - a number, a string, an array, an object...

Using store's onAction(handler) and onStateChanged(handler) methods, we can set a chain of reducers and a list of observers to state changes, correspondingly.

This example also shows how we can pass the initial state to a component's instance, using the init(state, children) method of a Component instance (in this example - Counter.init() ) .

In this example a few method signatures are also shown in action:

  • Component.init() has two arguments: initialState and children and both are optional
  • createComponent() has two arguments: viewFn and updateFn and, again, both are optional
  • viewFn has three arguments: state , children and dispatchFn ; last one is used to change component's internal state; second one is used for HOCs and will be handy to make configurations or to wrap the children with a markup or logic; first argument is just an internal component's state and, by the first call of the viewFn is equal to component's initialState , passed by Component.init() call
  • createStore(initialState) is used to create a Store instance, where initialState is pretty much anything
  • Store.dispatch() has exactly the same signature as the dispatchFn , used in viewFn

Instead of wrap-up

I hope this library is a little bit more than just an experiment and once it will be used for a great good!

Speeding-up algorithms with SSE urn:uuid:9e256529-9b15-56fc-b47c-2b49dabfb9d6 2017-02-21T00:00:00Z 2017-02-21T00:00:00Z

Have you ever asked anyone if assembly language might be useful nowadays? So, here’s the short answer: YES . When you know how your computer works (not a processor itself, but the whole thing - memory organization, math co-processor and others) , you may optimize your code while writing it. In this short article, I shall try to show you some use cases of optimizations, which you may incorporate with the usage of low-level programming.

Recently I was reading through my old posts and found out there is a gap in the article about SSE - the post did not cover some of the implementation caveats. I decided to fulfill this and re-publish a new version.

Artem Shubovych

Have you ever asked anyone if assembly language might be useful nowadays? So, here’s the short answer: YES . When you know how your computer works (not a processor itself, but the whole thing - memory organization, math co-processor and others) , you may optimize your code while writing it. In this short article, I shall try to show you some use cases of optimizations, which you may incorporate with the usage of low-level programming.

Recently I was reading through my old posts and found out there is a gap in the article about SSE - the post did not cover some of the implementation caveats. I decided to fulfill this and re-publish a new version.

Finding maximum

So, let’s start-off searching a maximum element in the array. Usually, it is nothing just iterating through the array, comparing each element with some starting value. For optimization reason and for the precision’s sake we set the initial value to the first array’s element. Like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max_value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Index-based search

What we could do firstly is to store not the search element itself, but its index:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max_index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This naive optimization has its effect (time in seconds; the value found in braces) :

<code><span class="line"><span>Value-based: 0.00732200 (0.99999827)</span></span>
<span class="line"><span>Index-based: 0.00674200 (0.99999827)</span></span></code>

Vector operations

This is quite a universal algorithm, which could be used for any type, which allows comparing. But let’s think abotu how we can speed up that code. First of all, we could split the array into pieces and find maximum among them.

There is a technology, allowing that. It is called SIMD - S ingle I nstruction - M ultiple D ata Stream. Simply saying, it means dealing with multiple data pieces (cells, variables, elements) with the use of a single processor’ instruction. This is done in processor command extension called SSE .

Note: your processor or even operating system may not support these operations. So, before continuing reading this article, be sure to check if it does. On Unix systems you may look for mmx|sse|sse2|sse3|sse4_1|sse4_1|avx in /proc/cpuinfo file.

SSE extension has a set of vector variables to be used. These variables (on the lowest, assembly level, they are called XMM0 .. XMM7 registers) allow us for storing and processing 128 bits of data as it was a set of 16 char , 8 short , 4 float/int , 2 double or 1 128-bit int variables.

But wait! There are other versions of SSE, allowing for different registers of a different size! Check this out:

SIMD extensions

MMX - hot 1997:

  • only integer items
  • vectors have a length of 64 bits
  • 8 registers, namely MM0 .. MM7

SSE highlights:

  • only 8 registers
  • each register has a size of 128 bit
  • 70 operations
  • allow for floating-point operations and vector’ elements

SSE2 features:

  • adds 8 more registers (so now we have XMM0 .. XMM15 )
  • adds 144 more operations
  • makes floating-point operations more precise

SSE3 changes:

  • adds 13 more operations
  • allows for horizontal vector operations

SSE4 advantages:

  • adds 54 more operations (47 are given by SSE4.1 and 7 more come from SSE4.2)

AVX - brand new version:

  • vector size is now 256 bit
  • registers are renamed to YMMi , while XMMi are the lower 128 bits of YMMi
  • operations now have three operands - DEST , SRC1 , SRC2 ( DEST = SRC1 op SRC2 )

SSE operations

So, I mentioned horizontal vector operations . But let’s do it in a series.

There are two SSE operation types: scalar and packed . Scalar operations use only the lowest elements of vectors. Packed operations deal with each element of vectors given. Look at the images below and you shall see the difference:

Horizontal operations deal on vectors in a different direction. Instead of operating on elements in the corresponding positions, these operate on elements in adjacent positions:

So there are six "types" of operations, as described above. They are:

  • operations, dealing with scalar or double values
  • operations, operating on all elements in a pack or on last elements of a pack
  • operations, handling values on corresponding or adjacent positions

To determine if an operation type, you just need to look at the last two characters of operation’s name:

HADDPS -> Horizontal ADD Packed Single-precision

Working with SSE

Images above describe how processor instructions (assembly commands) work. To map those onto C++ functions, you only need to replace assembly operation with the corresponding function from SSE headers (I'll cover that in just a second) . But the main goal of those explanations above was to give you an idea how operations themselves work and where do they store results.

To work with SSE we need to follow these three steps:

  1. load data into XMM registers
  2. perform all the operations needed on those XMM registers
  3. store data from XMMs into usual variables

To use vector operations, you shall need to have some header files included in your code, as well as compiler flags, turned on.

These are header files:

  • mmintrin.h - MMX
  • xmmintrin.h - SSE
  • emmintrin.h - SSE2
  • pmmintrin.h - SSE3
  • smmintrin.h - SSE4.1
  • nmmintrin.h - SSE4.2
  • immintrin.h - AVX

None of the header files requires all the previous ones to be included too. Compiler flags are -mmmx , -msse , -msse2 , -msse3 , -msse4 , -mavx , correspondingly. As with header files, none of these flags requires previous ones to be turned on.

Data types

There are three "standard" data types within SSE:

  1. __m128 , which is SSE’s float[4]
  2. __m128d corresponds to double[2]
  3. __m128i represents one of these: char[16] , short int[8] , int[4] or uint64_t[2]

Each of them needs to be converted from or to standard C++ types with its own intrinsic (SSE operation).

Intrinsics

SSE operations in C++ are named this way: _mm_{OPERATION}_{SUFFIX} . The operation is the operation on vectors you want to perform. The suffix is a set of flags for a processor, showing in what way it should work with operands (packed/scalar, single-/double- precision, etc.) .

For optimization’s sake, it is better if operands for intrinsincs are aligned in memory for base 16. But do not worry, the compiler will automatically decide if the variable is aligned or not and perform all the needed operations itself.

For loading data into SSE vectors there are four intrinsics:

  1. _mm_set_ps(4.0, 3.0, 2.0, 1.0) -> [4.0, 3.0, 2.0, 1.0]
  2. _mm_set1_ps(3.0) -> [3.0, 3.0, 3.0, 3.0]
  3. _mm_set_ss(4.0) -> [0.0, 0.0, 0.0, 4.0]
  4. _mm_setzero_ps() -> [0.0, 0.0, 0.0, 0.0]

And like those, there are very similar intrinsics for storing data from vectors in a usual C++ types (in the examples below assume working with the same __m128 t = [4.0, 3.0, 2.0, 1.0] ) :

  1. _mm_store_ps(float[4], __m128) -> [4.0, 3.0, 2.0, 1.0]
  2. _mm_store_ss(float*, __m128) -> 1
  3. _mm_store_ss(float*, __m128) -> [1.0, 1.0, 1.0, 1.0]
  4. double _mm_cvtsd_f64(__m128d) -> 1
  5. int _mm_cvtsi128_si32(__m128i) -> 1 (for given __m128i [4, 3, 2, 1] )

Finding maximum

So, let’s get back to finding the maximum in an array. For this task we will search maximums on each 4 elements of our array, storing them in the XMMi register:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max_sse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__m128</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_setzero_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_max_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    _mm_store_ss</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

But if you run this code, you may notice it returns the maximum, not in 100% of cases. This is because we are storing four maximums between each portion of an array . So, only one of those four is the maximum. But how can we find the maximum among four numbers? Running a loop seems obvious but not effective enough…

We may use the shuffle intrinsic! That is, cycle-shifting vector three times and finding maximum between that shifted vector and its previous value. That will give us the maximum in all four positions of our vector.

Here is a better explanation:

If we want to cycle-shift a 4-number array, we use _mm_shuffle_ps intrisinc.

It takes 3 parameters: m1 , m2 , and mask . First two are four-word (four-number) packs. The mask consists of four numbers and shows which elements of pack m2 and which elements of pack m1 will form the result. This mask could be obtained using _MM_SHUFFLE(z, y, x, w) macro, which forms an integer according to the formula (z &#x3C;&#x3C; 6) | (y &#x3C;&#x3C; 4) | (x &#x3C;&#x3C; 2) | w .

Given those definitions, the call m3 = _mm_shuffle_ps(m1, m2, _MM_SHUFFLE(z, y, x, w)) is equal to the formula m3 = (m2(z) &#x3C;&#x3C; 6) | (m2(y) &#x3C;&#x3C; 4) | (m1(x) &#x3C;&#x3C; 2) | m1(w) .

So we want to shift a pack by one element right, like this: [4, 2, 3, 1] => [2, 3, 1, 4] . We need to pass the initial pack, [4, 2, 3, 1] twice: _mm_shuffle_ps([4, 2, 3, 1], [4, 2, 3, 1], mask) and form a mask, which will use elements [2, 3] for the higher words of a result and elements [3, 1] for the lower words. These elements can be then indexed as follows:

<code><span class="line"><span>+-----------+---------+</span></span>
<span class="line"><span>| index     | 3 2 1 0 |</span></span>
<span class="line"><span>+-----------+---------+</span></span>
<span class="line"><span>| element   | 4 2 3 1 |</span></span>
<span class="line"><span>+-----------+---------+</span></span></code>

So to get the pair [2, 3] we need elements with indices [2, 1] . And to get the pair [1, 4] we need elements with indices [0, 3] .

Given that, we can use macro _MM_SHUFFLE() to generate the mask: _MM_SHUFFLE(2, 1, 0, 3) . And the final formula looks like this: _mm_shuffle_ps(m1, m2, _MM_SHUFFLE(2, 1, 0, 3)) .

<code><span class="line"><span>+--+---------+</span></span>
<span class="line"><span>|  | 3 2 1 0 |</span></span>
<span class="line"><span>+------------+</span></span>
<span class="line"><span>|m1| 4 2 3 1 |</span></span>
<span class="line"><span>+------------+</span></span>
<span class="line"><span>|m2| 4 2 3 1 |</span></span>
<span class="line"><span>+------------+</span></span>
<span class="line"><span>|m3| 2 3 1 4 |</span></span>
<span class="line"><span>+------------+</span></span></code>

And our max function in pseudo-code looks like this:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// given val = [4, 2, 3, 1]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    val </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_shuffle_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _MM_SHUFFLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_max_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Which will be executed like this:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// preparation</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// i = 0</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _mm_shuffle_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _MM_SHUFFLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // = [2, 3, 1, 4]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _mm_max_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // = [4, 3, 3, 4]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// i = 1</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _mm_shuffle_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _MM_SHUFFLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // = [3, 1, 4, 2]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _mm_max_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // = [4, 3, 4, 4]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// i = 2</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _mm_shuffle_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _MM_SHUFFLE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // = [1, 4, 2, 3]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _mm_max_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // = [4, 4, 4, 4]</span></span></code>

The _MM_SHUFFLE(2, 1, 0, 3) call could be expanded to (2 &#x3C;&#x3C; 6) | (1 &#x3C;&#x3C; 4) | (0 &#x3C;&#x3C; 2) | 3 , which equals to 147 or 147 in HEX.

And here is the final C++ implementation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max_sse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__m128</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_setzero_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_max_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_max_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_shuffle_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">93</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    _mm_store_ss</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And how about integers?

The code for finding maximum with SSE among integer array is very, very similar to the previous one - you just need to decorate intrinsics with a different prefix and change store operation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> max_sse_int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128i </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__m128i</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128i maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_setzero_si128</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_max_epi32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        maxval </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_max_epi32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_shuffle_epi32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">93</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_cvtsi128_si32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxval</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Profit?

If we compare the results of all three methods - usual loop, index-based searching and SSE, we may see something like this (I ran these tests on my laptop’s i7 processor on one million random float/int values) :

<code><span class="line"><span></span></span>
<span class="line"><span>=== Looking for a maximum element in a list of 1000000 floats ===</span></span>
<span class="line"><span>* Value-based: 0.00382500 sec; max = 0.99999923</span></span>
<span class="line"><span>* Index-based: 0.00282200 sec; max = 0.99999923</span></span>
<span class="line"><span>* SSE: 0.00131300 sec; max = 0.99999923</span></span>
<span class="line"><span>=== Looking for a maximum element in a list of 1000000 integers ===</span></span>
<span class="line"><span>* Value-based: 0.00384200 sec; max = 99</span></span>
<span class="line"><span>* Index-based: 0.00298300 sec; max = 99</span></span>
<span class="line"><span>* SSE: 0.00130400 sec; max = 99</span></span>
<span class="line"><span></span></span></code>

Here you can see that index-based searching gives some speeding-up (around 15% ). But the real speed boost is gained with SSE (almost 4 times !).

Calculating the sum

Now let’s try something harder - calculating a sum of array’s elements. Here we will use the horizontal vector operations. But first, here’s the general algorithm:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        res </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Simple enough, huh? Now let’s use the SSE’s _mm_add_ps intrinsic. Running it on each pack of four elements will give us the summary vector of four floats:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum_sse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__m128</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_setzero_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_add_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    _mm_store_ss</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

But if we now add the elements of that vector horizontally to themselves, we would then have the two-element vector. Adding it to itself will give us the final single-element vector:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum_sse</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__m128</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128 vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_setzero_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_add_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_hadd_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_hadd_ps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    _mm_store_ss</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Nice, isn’t it? But wait! Integers are available too! And they need their special intrinsics! Have no fear, nothing that different here, only the prefixes are different:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128i </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f4 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__m128i</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    __m128i vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_setzero_si128</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_hadd_epi32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_hadd_epi32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    vec_sum </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_hadd_epi32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _mm_cvtsi128_si32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec_sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And, just to approve our assumption of speeding-up, here’s the benchmarking (on one million of elements) :

<code>Value-based: 0.00853100 (500245.28125000)
SSE: 0.00319800 (500243.50000000)
Value-based on integers: 0.00773100 (49453512)
SSE on integers: 0.00274800 (49453512)
</code>

Now here is a thing to think about: the assembly output of the sum function is much shorter than the one for the sum_sse function:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sum(float*, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">):</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        push</span><span style="color:#D20F39;--shiki-dark:#E78284">    rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">28</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">esi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pxor</span><span style="color:#D20F39;--shiki-dark:#E78284">    xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">   DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">28</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jge</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cdqe</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#D20F39;--shiki-dark:#E78284">   xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#D20F39;--shiki-dark:#E78284">   xmm1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        addss</span><span style="color:#D20F39;--shiki-dark:#E78284">   xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">   DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#D20F39;--shiki-dark:#E78284">   xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pop</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        ret</span></span></code>

vs

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sum_sse(float*, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">):</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        push</span><span style="color:#D20F39;--shiki-dark:#E78284">    rbp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rsp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sub</span><span style="color:#D20F39;--shiki-dark:#E78284">     rsp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">72</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">184</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">188</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">esi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pxor</span><span style="color:#D20F39;--shiki-dark:#E78284">    xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">   DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">164</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">184</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        pxor</span><span style="color:#D20F39;--shiki-dark:#E78284">    xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">188</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        test</span><span style="color:#D20F39;--shiki-dark:#E78284">    eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmovs</span><span style="color:#D20F39;--shiki-dark:#E78284">   eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">edx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sar</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cmp</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jge</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        cdqe</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        sal</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rdx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">rdx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">48</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">48</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        addps</span><span style="color:#D20F39;--shiki-dark:#E78284">   xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        add</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        jmp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     .L5</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">L3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">80</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">96</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">80</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        haddps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">96</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        nop</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">112</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">128</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">112</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        haddps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">128</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        nop</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        lea</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">164</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">     QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">136</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#D20F39;--shiki-dark:#E78284">  xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">16</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movaps</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  XMMWORD PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">160</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#D20F39;--shiki-dark:#E78284">   xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">160</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        mov</span><span style="color:#D20F39;--shiki-dark:#E78284">     rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">136</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">   DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">xmm0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        nop</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        movss</span><span style="color:#D20F39;--shiki-dark:#E78284">   xmm0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">164</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        ret</span></span></code>

And yet, the performance of that longer piece of code is still higher!

Limitations?

Please note the difference between sums calculated with naive loop and the one calculated with SSE: they do differ . This is caused by a way computer work nowadays. Actually, how they store floating-point values. Since computers deal with binary system, they can not simply store all those digits after point in the memory and operate on them effectively.

Remember, how integers are stored in a binary system? Say, 14:

<code>+-----------+------------------------+
|     n     | 5   4   3   2   1   0  |
+------------------------------------+
| pow(2, n) | 32  16  8   4   2   1  |
+------------------------------------+
|   fits?   | N   N   Y   Y   Y   N  |
+------------------------------------+
|   14  =   | 0 + 0 + 8 + 4 + 2 + 0  |
+-----------+------------------------+
| bin(14) = | 0   0   1   1   1   0  |
+-----------+------------------------+
</code>

E.g. binary representation of 14 is: 14<sub>2</sub> = 001110 . Leading zeroes could be skipped in a binary system (as there might be as many of those as you wish) .

A similar thing happens to floating-point numbers: the difference is that computer stores the negative powers of two:

<code>+------------+-----------------------------------------+
|     n      | 5        4       3      2     1    0    |
+------------------------------------------------------+
| pow(2, -n) | 0.03125  0.0625  0.125  0.25  0.5  1.0  |
+------------------------------------------------------+
|   fits?    | N        N       Y      Y      Y    N   |
+------------------------------------------------------+
|   0.9  =   | 0    +   0  +  0.125 + 0.25 + 0.5 + 0   |
+------------------------------------------------------+
| bin(0.9) = | 0        0       1      1      1    0   |
+------------------------------------------------------+
</code>

As you can see, using 5 bits is not enough to represent 0.9, but only 0.875 . Even if we use 32 bits (which is just a float data type in C) , we will have 0.011001100110011001100110011001110<sub>2</sub> , which is 0.8999999999068677 , but still, it's not exactly what we wanted. On 64 bits ( double type in C) it is better, 0.8999999999999999 , but, again, not exact value. And if we try adding one million unprecise numbers, we will probably get the unprecise result.

Another big limitation of SSE is that initial data should be aligned to contain the number of elements, which is a multiply of either 2 or 4 (depending on the SSE operation type you are using - scalar or double) .

Resources

  1. Code vectorization with SSE
  2. Intel intrinsics guide
  3. Examples source code
Functional web urn:uuid:198f4f49-70bf-5f5d-897d-185c08d08090 2017-02-14T00:00:00Z 2017-02-14T00:00:00Z

In last couple of years the functional programming paradigm became very popular. A huge amount of libraries, tools, tutorials and blog posts appeared. Although the paradigm itself is rather old (lambda calculus was developed around 1930 and the Lisp language was introduced in 1950) , its popularity blew up rapidly somewhere in 2014-2016 and that's what is happening right now. Probably one of the most powerful influencers, giving FP (functional programming) that thrust is web development. Since Facebook introduced React , the community started incorporating many things from FP with React - including Redux and Immutable.js . But there are much more interesting things which were invented on this wave of FP popularity. One of them is Elm .

This is a story how I implemented invented yet another web framework wheel.

Artem Shubovych

In last couple of years the functional programming paradigm became very popular. A huge amount of libraries, tools, tutorials and blog posts appeared. Although the paradigm itself is rather old (lambda calculus was developed around 1930 and the Lisp language was introduced in 1950) , its popularity blew up rapidly somewhere in 2014-2016 and that's what is happening right now. Probably one of the most powerful influencers, giving FP (functional programming) that thrust is web development. Since Facebook introduced React , the community started incorporating many things from FP with React - including Redux and Immutable.js . But there are much more interesting things which were invented on this wave of FP popularity. One of them is Elm .

This is a story how I implemented invented yet another web framework wheel.

TL;DR

React

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> App</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Component</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">props</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(props)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counter</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  increment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counter</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">counter </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  decrement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> counter</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">counter </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  render</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">increment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Increment</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">decrement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Decrement</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Counter: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">counter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ReactDOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">App</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Run this code

React + Redux

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">props</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INCREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Increment</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DECREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Decrement</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Counter: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  switch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INCREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DECREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Redux</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createStore</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(update)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> render</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ReactDOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">App</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">subscribe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(render)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Code

Elm

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Html</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">beginnerProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> div</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> button</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Html.Events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onClick</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">initialState </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">view state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onClick Increment </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Increment"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onClick Decrement </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Decrement"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Counter:"</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">toString state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ]</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Increment</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Decrement</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update msg state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Increment </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Decrement </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  beginnerProgram </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> initialState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Compiled code

Mithril

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> App </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    view</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'main'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'decrement'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> onclick</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$</span><span style="color:#179299;--shiki-dark:#81C8BE">--</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'increment'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> onclick</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'p'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Counter: '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mount</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> App)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Code

Cycle

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xstream</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> div</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> makeDOMDriver </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CycleDOM</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">sources</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decrement$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sources</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DOM</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'click'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mapTo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> increment$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sources</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DOM</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'click'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mapTo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">merge</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(decrement$</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> increment$)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action$</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fold</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vtree$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> div</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      button</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.decrement'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      button</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.increment'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      p</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Counter: '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vtree$ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Cycle</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> makeDOMDriver</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'body'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Code

libc

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> initialState </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (message </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INCREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (message </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DECREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> click</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'INCREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> click</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'DECREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `Count: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> app </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(initialState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">app</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mount</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Code

React + Redux

Let's start-off by writing a simple "counter" application with the well-known React + Redux bundle.

React

The purpose of Facebook's React is to provide an interface to a virtual DOM, which allows users to track updates to the application views and perform DOM operations to update views with a minimal operation overhead . In other words, we do not need to remove all the DOM nodes and create new ones from scratch when we can update a single property in a single DOM node. It might look like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> App</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Component</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">props</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    super</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(props)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  increment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  decrement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    &#x3C;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">div</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      &#x3C;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">button</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">increment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Increment</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      &#x3C;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">button</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">decrement</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Decrement</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      &#x3C;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">div</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">></span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">Counter</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;font-style:italic;--shiki-dark:#C6D0F5;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">/div</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span></span>
<span class="line"><span style="color:#04A5E5;--shiki-dark:#99D1DB">    &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">/div</span><span style="color:#04A5E5;--shiki-dark:#99D1DB">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ReactDOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">App</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Run this code

Redux

Redux is an ancestor of Facebook's Flux architecture and library. Flux' main goal was to standardize the way application stores its state and handles state updates:

  • application state is stored in stores
  • to update application state, we dispatch messages to corresponding stores
  • to reflect application state changes, we subscribe on the store state changes

Than comes Redux and says "hey! we probably can do that with just a single store!" . And whilst Flux did not forbid state updates to modify the state objects themselves, Redux states clearly: "you may not change state directly - rather you just calculate a new value for it and I take care of everything else" .

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">props</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> props</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INCREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Increment</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onClick</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DECREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Decrement</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Counter: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> action</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  switch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (action</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INCREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DECREMENT'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> store </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Redux</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createStore</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(update)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> render</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ReactDOM</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">App</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> store</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">render</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">store</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">subscribe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(render)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Run this code

Elm

Elm is ML-like (Haskell-like) language, which compiles to JS, and provides developer with a runtime, allowing one to build web applications in a functional, strongly-typed language. Elm enforces its way of building web applications, where each web app is a combination of three entities:

  1. model , which is basically just a structure of application state
  2. update function , which takes current state and an event ( action in terms of Redux; message in terms of Elm; an object, representing user action or any other event) and provides the new value for app state (model)
  3. view function , which converts current app state into a virtual DOM tree
Elm workflow

Elm runtime handles everything else - passing messages to the update function, comparing the actual DOM tree with the one, provided by a view function and performing all DOM tree manipulations.

Elm can be compared to React + Redux + ML-language combination.

Let's take a look at our sample application, written in Elm:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Html</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">beginnerProgram</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> div</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> button</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> Html.Events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exposing </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">onClick</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">initialState </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">view state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onClick Increment </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Increment"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onClick Decrement </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Decrement"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> div </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Counter:"</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">toString state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ]</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">type</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Msg</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Increment</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Decrement</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">update msg state </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  case</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">of</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Increment </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Decrement </span><span style="color:#179299;--shiki-dark:#81C8BE">-></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  beginnerProgram </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> model </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> initialState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Run compiled version of this code

In this example, we first define initial application state, which is just integer number of zero.

Then we describe the view of our application, how the application will display the current state in HTML. This is the battle field of a view function.

After that we define possible actions (or messages in terms of Elm) . It would be either Increment or Decrement action with no additional parameters.

Right after that we define how each message will affect application state. Since our application' state is only an integer number, the update function will return the new state given the current state value and an action.

Lastly we create our application, providing Elm with all the entities we defined above.

I found this code to be more clear, than in case with React + Redux, since in case we'd like to write something more complex, we don't need to use tons of mapping/reducing/selecting functions, split into a huge bunch of files. I'll cover more complex examples later on.

Mithril

Mithril is a tiny JS framework, whose main feature is virtual DOM. Just take a look at a sample application:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> App </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    view</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'main'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'decrement'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> onclick</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$</span><span style="color:#179299;--shiki-dark:#81C8BE">--</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'increment'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> onclick</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        m</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'p'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Counter: '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mount</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> App)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Run this code

This is much less code than in case with React + Redux, isn't it?

Cycle

Cycle is a reactive framework; kind of React + Rx. This means an application is basically a view function, subscribed to all the events allowed in your application. An example straight from cycle website:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xstream</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">default</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> div</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> makeDOMDriver </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> CycleDOM</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">sources</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decrement$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sources</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DOM</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'click'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mapTo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> increment$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sources</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DOM</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">select</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">events</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'click'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mapTo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> xs</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">merge</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(decrement$</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> increment$)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> action$</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fold</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">acc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> acc </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vtree$ </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count$</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> div</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      button</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.decrement'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      button</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.increment'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      p</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Counter: '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vtree$ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Cycle</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(App</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DOM</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> makeDOMDriver</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'body'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Run this code

Let me explain this source, since this might not be obvious.

First, Cycle (or, actually, RxJS ) operates on event streams . In this particular application there are two event streams: clicks on the "Increment" button and clicks on the "Decrement" button. So we first make all "click" events on the "Decrement" button (expressed by sources.DOM.select('.decrement').events('click') ) to become just -1 number (which is made by mapping each event to a value -1 , eventStream.map(-1) ). Then we do the similar thing to the clicks on the "Increment" button, but transform each event to 1 (positive) number.

Now, we merge both streams into a single one (thus both "Increment" and "Decrement" clicks will come from a single event stream, namely action$ ).

Then we transform our unified event stream action$ into a stream of a single value by adding all the events (values) from action$ stream.

And lastly, we transform our single-value stream count$ into a virtual DOM tree and update the real dom, if needed.

Event streams

Here's what should be explained regarding those event streams: a stream is a series of some values. That's it. Nothing more. When a value is added to a stream (an event is fired) , all the transformations are run as they are nothing but observers to the "on value appeared" event. Ans since all those transformations can be chained, we can imagine each transforming function is just a new event listener for that "on value appeared" event. And each transformation will provide us with a new stream, what allows us to add many different listeners to the same stream.

Here's a diagram, showing all the transformations:

Event transformations diagram

So once a click event (on one of two buttons, of course) appears, it is transformed to either -1 or 1 , depending on the button which fired that event; then this number is added to the existing (which might appear to be empty) event stream action$ ; then the sum is calculated over all the numbers in that stream; then the sum is transformed into a virtual DOM tree; and lastly, the virtual DOM tree is returned from a view function and Cycle does its job to update the actual DOM. And since there always will be a different value of sum in our example, the DOM will always be updated.

libc

So far I've covered four different implementations of a very simple yet interactive web application. Some of them require a whole bunch of libraries to be injected into a page (in case with React+Redux+whatever, Cycle), some of them introduce a whole new approach to create interactive applications (Cycle, Elm, Mithril). Based on that, I created my own micro library, which inherits most interesting features of frameworks discussed above.

I called it libc .

The same "counter" application, written in libc looks like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> initialState </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (message </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'INCREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (message </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'DECREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> view</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> click</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'INCREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Increment'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> click</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dispatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'DECREMENT'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Decrement'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'div'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `Count: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  ]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> app </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(initialState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> update</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> view)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">app</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mount</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Run this code

All the DOM nodes are created using the array returned, which should match pattern [tag, {attributes}, (text | [children])) (just like Mithril uses m() function or Elm uses div and other helper functions) . Originally, libc used c() helper function to do that (similar to Mithril's m() function) , and that's why it was called libC .

The library makes use of a VirtualDOM approach to create a virtual DOM tree and chech which nodes/node properties need changes and reflect only the needed changes in a real DOM tree.

libc uses the message -> update -> view chain, just like Elm does. The inner application state is handled similarly to Redux - application has only one store, which contains application state. And the update() function just calculates the new value for a state, without actually assigning it. Library then checks whether state needs to be updated or not (using Object.deepEqual method, exposed by a library) . If the new state value is different from the existing one - the state is replaced with a new value and the view() function is being called with a new state value. view function returns the new value of a virtual DOM tree. Library then checks whether it needs to update actual DOM tree or not.

There are however couple highlights regarding libc :

  • it can create arbitrary tags (DOM nodes) within the view() function (the first element in each array is tag name, which could be pretty much anything) , so it's quite easy to use it in couple with other libraries (such as Angular-material, React or Polymer, for instance)
  • properties, whose value is a function are automatically mapped to event listeners; taking into account that property names could be arbitrary as well, you may add event listeners to your custom events
  • again, property names could be arbitrary, so you can use even angular ones if you want: ['div', { 'ng-repeat': 'item in items' }, '{{item.name}}']
  • both properties and children or text arguments are optional; thus you can create empty DOM elements: ['hr']
  • to enable communication with your applications from the outside, application instance, returned by the createApplication() function, has the dispatch(message) method

In later posts I'll provide more examples of using libc .

Clojure guards urn:uuid:527fa853-05de-58b8-ab3d-94974fb5342b 2016-12-21T00:00:00Z 2016-12-21T00:00:00Z Clojure guards Artem Shubovych

Once I wanted to have something like a pretty "match" operator from Scala (or Rust, or C# 7), but in Clojure. In this blog I explore some solutions for that available in Clojure world.

Use case

Generally, you would use pattern matching as a neat syntax for multiple if..else or switch..case statements. Consider this example of transforming values between two enums:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entityType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entityType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UNKNOWN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This could be written neatly with a switch..case statement:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">switch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    case</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    default</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UNKNOWN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

In C# starting with version 7 you could write this using switch expression:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entityType </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">switch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    DBEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ISSUE</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    DBEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">SUBTASK</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UNKNOWN</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

But what if you have multiple conditions to check?

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entityType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">canEdit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entityType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">canEdit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> UIEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UNKNOWN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This can not be converted to switch..case nicely. But with switch expressions (or rather, pattern matching, in general) you can do something like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entityType </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">switch</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ISSUE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">canEdit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISSUE</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">SUBTASK</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">canEdit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> DBEntityType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">SUBTASK</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    _ </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> UIEntityType</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">UNKNOWN</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Using cond

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; Note how this method does not check the `n > 3` case</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testFn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cond</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered 1!"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered two!"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered three!"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        :else </span><span style="color:#40A02B;--shiki-dark:#A6D189">"You entered a big number!"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> complexFn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entityType user permissions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cond</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">and</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entityType :db-issue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">can-edit?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions user :db-issue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :ui-issue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">and</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entityType :db-subtask</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">can-edit?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions user :db-subtask</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :ui-subtask</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        :else :ui-unknown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span></code>

Using condp

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; Note how this method does not check the `n > 3` case</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testFn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">condp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = n</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        1</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered 1!"</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        2</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered two!"</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        3</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered three!"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "You entered a big number!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> complexFn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entityType user permissions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">condp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entityType </span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :db-issue </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">can-edit?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions user :db-issue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :ui-issue</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :db-subtask </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">can-edit?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> permissions user :db-subtask</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :ui-subtask</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        :ui-unknown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span></code>

Using guard macro

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> generateGuardBody</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Generates the function body required to support the guard macro"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">thisBranch remainingBranches</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">split-at</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            testCond </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">first</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisBranch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            testResult </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">second</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> thisBranch</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            elseFunc </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">empty?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> remainingBranches</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">                false</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">  1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">count</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> remainingBranches</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">first</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> remainingBranches</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">generateGuardBody</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> remainingBranches</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        `(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if ~testCond</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ~testResult</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ~elseFunc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defmacro</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> defguardfn</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Creates a haskell-style guarded function"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fnName args &#x26; body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    `(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ~fnName ~args</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ~</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">generateGuardBody</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defmacro</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> guard</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "Allows inline guard syntax without surrounding defn"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26; body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    `~</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">generateGuardBody</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defguardfn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testFn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered 1!"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered two!"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered three!"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "You entered a big number!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">testFn</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defguardfn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fib </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fib</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fib</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testFn-2 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">guard</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "One!"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Two!"</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">        true</span><span style="color:#40A02B;--shiki-dark:#A6D189">  "Something Else!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fib </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">range</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">testFn-2</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; "Something else!"</span></span></code>

Using multimethods

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; Implementing factorial using multimethods Note that factorial-like function</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; is best implemented using `recur` which enables tail-call optimization to avoid</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; a stack overflow error. This is a only a demonstration of clojure's multimethod</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;; identity form returns the same value passed</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defmulti</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factorial identity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defmethod</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factorial </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#FE640B;--shiki-dark:#EF9F76">  1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defmethod</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> factorial :default </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">num</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> num </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorial</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dec</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> num</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorial</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; => 1</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorial</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; => 1</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorial</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; => 6</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factorial</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; => 5040</span></span></code>

Using core.match

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> div3? </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">zero?</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rem</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :guard even?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :a0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">b</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :guard </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">odd? div3?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _ _</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :a1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:or </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :a0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:or </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :a1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;=> :a1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:a </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:a </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:or </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)}]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :a0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:a </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:or </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)}]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :a1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;=> :a1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">match</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [[[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :a0</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    [[([</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :as b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:a1 a b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">;=> [:a1 2 [1 2]]</span></span></code>
Big O notation urn:uuid:339e110e-ae17-5124-b02b-f9bf1f85b005 2016-08-25T00:00:00Z 2016-08-25T00:00:00Z

The best big O notation explanation I've ever saw I've found on... Google Play Market! I was hanging around, looking for the suggested software and, for some reason, I've decided to install some educational application for programmers. And here's what I've found...

Artem Shubovych

The best big O notation explanation I've ever saw I've found on... Google Play Market! I was hanging around, looking for the suggested software and, for some reason, I've decided to install some educational application for programmers. And here's what I've found...

Big O notation shows, how many steps or memory units will the algorithm use to complete, at its maximum. Here's an example:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> someAlgorithm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 1</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  doSomething</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    doSomething</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    doSomething</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> t</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      doSomething</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Let's take a look at each of four algorithm parts. Part 1 just calls some function, doSomething() . Let's assume it takes some constant amount of time to complete, C . The time complexity of calling a function, which uses constant time to complete is O(1) . So part 1 will take O(1) time to complete.

Part 2 has a loop, which has exactly 10 iterations, calling doSomething() at each iteration. As we've discussed above, this part takes 10 * C (ten calls of doSomething() function, which takes C steps to complete) steps. This is a constant value too, so part 2 of the function myAlgorithm() will have the complexity of O(1) .

Part 3 has a loop, whose number of iterations relies on the input parameter of myAlgorithm() , namely n . We do not know, what value the n will take. But as it increases, the steps, needed for this part to complete increases too. So the complexity of this part will be O(n) .

Part 4 has two nested loops. As in the previous case, when n increases, the steps needed by this part to complete will increase even faster: for n = 1 it will take exactly C steps to complete (recall: the complexity of doSomething() is C ); for n = 2 it will take 2 * 2 * C = 4 * C steps to complete; for n = 10 the amount of steps would be 10 * 10 * C = 100 * C . One can notice that the complexity equals to n * n * C . This is quadratical complexity, denoted as O(n^2) .

The final complexity of an algorithm could be calculated by easily adding all those parts' complexities: O(1) + O(1) + O(n) + O(n^2) . But here's the trick: if the n is relatively small (like, 10 or 100 ), the difference between O(1) and O(n) is huge (noticeable, at least). But if we say the value of n is insanely large (like, billiards), we may not notice the O(1) is just nothing, compared to O(n) . And O(n) is just nothing, when compared to O(n^2) . And here comes the rule: total complexity of an algorithm is the maximum needed amount of steps to complete. Just as follows:

  • O(C) = O(1)
  • O(1) + O(n) = O(n)
  • O(n) + O(n^2) = O(n^2)

Here comes the comparison of the known complexities: O(1) &#x3C; O(log n) &#x3C; O(n) &#x3C; O(n*log n) &#x3C; O(n^m) .

But we can measure not time consumption only, using the big O notation. It is also handy for memory complexity measurements.

Here the same rules apply, except of "steps to complete" we use "memory cells allocated" . So we will count the amount of allocated memory. This is mostly used by lists, not by objects and structures (as they always use the same memory amount). Check this out:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">struct</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Foo</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  float</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Both Moo and Foo will use the same amount of memory initially (since pointers in C++ are just integer memory addresses' values and floats use same 4 bytes - just as integers do). But depending on how many memory we will allocate for Foo.d we will get the different values. Consider the continuation of this example below:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> myAlgorithm</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 1</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  Foo </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">foo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Foo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 2</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  foo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">d </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  int</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  // part 4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  int</span><span style="color:#179299;--shiki-dark:#81C8BE"> **</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Here, in part 1, we have just an instance of Foo class, which uses 3 * int + float* = 3 * 1 + 1 = 4 memory cells. As in case with time complexity, this amount is constant, thus it has O(1) memory consumption.

In part 2, however, we extend this amount by placing 10 memory cells into foo.d field, but this does not change much, as foo will use constant memory cells anyway. So, part 2 has memory complexity of O(1) too.

In part 3 we create a new array, and its size depends on function's argument n , so its memory consumption is O(n) .

In part 4 we create a two-dimensional array, whose size is n * 15 . We can split its size into two components: O(n) * O(15) = O(n) , because 15 is 15 no matter what.

And the total memory complexity of the algorithm is O(1) + O(1) + O(n) + O(n) = O(n) .

For even more simple O(*) calculus, replace the + operator with the min operator: memory complexity of myAlgorithm() is max(O(1), O(1), O(n), O(n)) = O(n) .

Chicken in Blender urn:uuid:883d6fba-ac55-5827-a488-feda1d053272 2016-03-05T00:00:00Z 2016-03-05T00:00:00Z Chicken in Blender Artem Shubovych

This is a chicken. This 3D model I've made in 3.5 hrs in Blender (with texturing) .

Taking into account the fact I've started learning Unity 3D , I will possibly use this in the remake of my old Shoot Them! game. Like this (early preview, made with Unity 3D in ~3 hrs) :

Two sides of web application. Part 2: sketching urn:uuid:4abf918a-fe8b-5cdb-90d5-d0688f4f2588 2016-02-11T00:00:00Z 2016-02-11T00:00:00Z
Funny image

General architecture

The first thing we need to think of is how we'll be gathering the information about users. It's quite easy - we just need to get a request from a visitor. Of any kind - it may be a request to get an image, a file, a stylesheet or a script.

Then we'll just parse headers from that request and save the extracted data in the database. The only problem here is: how to get unique key from each request? . We may use visitor's IP address. It's the easiest way.

Artem Shubovych
Funny image

General architecture

The first thing we need to think of is how we'll be gathering the information about users. It's quite easy - we just need to get a request from a visitor. Of any kind - it may be a request to get an image, a file, a stylesheet or a script.

Then we'll just parse headers from that request and save the extracted data in the database. The only problem here is: how to get unique key from each request? . We may use visitor's IP address. It's the easiest way.

Now, let’s decide what pages will our application have and what will they look like:

<code>&#x3C;div class="col-xs-12 col-md-3">
    &#x3C;a href="/images/two-sides-of-web-application/part1/screen2.webp">
        &#x3C;img src="/images/two-sides-of-web-application/part1/screen2.webp" loading="lazy" alt="page 2" class="image-responsive">
    &#x3C;/a>
&#x3C;/div>

&#x3C;div class="col-xs-12 col-md-3">
    &#x3C;a href="/images/two-sides-of-web-application/part1/screen3.webp">
        &#x3C;img src="/images/two-sides-of-web-application/part1/screen3.webp" loading="lazy" alt="page 3" class="image-responsive">
    &#x3C;/a>
&#x3C;/div>

&#x3C;div class="col-xs-12 col-md-3">
    &#x3C;a href="/images/two-sides-of-web-application/part1/screen4.webp">
        &#x3C;img src="/images/two-sides-of-web-application/part1/screen4.webp" loading="lazy" alt="page 4" class="image-responsive">
    &#x3C;/a>
&#x3C;/div>
</code>

Templates

Let's create a set of pages, we described above. They will be used later to display real data, but for now we'll stub the real data with constants.

To make our prototyping smooth and fast, we'll use Twitter Bootstrap . We've installed it already with Bower , so we'll be just using it. We need to implement these pages only:

  • landing page
  • sign up / sign in page
  • account settings page
  • apps list page
  • application page
  • application create / edit page

Six pages, huh? Let's do it quick:

src/views/layouts/default.jade :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doctype html</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">lang</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"en"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    head</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> head</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            title</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStats</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            link</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">rel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"stylesheet"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bootstrap/dist/css/bootstrap.css"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            link</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">rel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"stylesheet"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bootstrap/dist/css/bootstrap-theme.css"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            script</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bootstrap/dist/js/bootstrap.js"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    body</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body</span></span></code>

src/views/index.jade :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> layouts/default.jade</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .jumbotron</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        h1</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.display-3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Welcome to ourStats!</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        p</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.lead</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> This is a simple stats application</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        hr</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.m-y-md</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        p</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.lead</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            .row</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                .col-xs-12.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    a</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-primary.btn-lg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"#"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> role</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"button"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Sign in</span></span></code>

src/views/new-session.jade :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> layouts/default.jade</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-4.col-md-offset-1.well</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Sign up</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            form</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Your name"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"email"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Email"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password confirmation"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-primary</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Sign up</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-md-2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-4.well</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Sign in</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            form</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"email"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Email"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-success</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Sign in</span></span></code>

src/views/edit_account.jade :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> layouts/default.jade</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row.m-t-md</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-4</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Account settings</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            form</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Your name"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password confirmation"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-success</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Save</span></span></code>

src/views/application_list.jade :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> layouts/default.jade</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row.m-t-md</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-4</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Your applications</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            ul</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                li</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/application_details.html"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Test application #1</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                li</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/application_details.html"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Test application #2</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                li</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/application_details.html"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Test application #3</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                li</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/application_details.html"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Test application #4</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                li</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    a</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/application_details.html"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Test application #5</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-md-offset-2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-6</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Application stats</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> New users:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            .progress</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                progress</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.progress-bar.progress-bar-success</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">role</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"progress"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> style</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"width:30%"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

src/views/application_details.jade :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> layouts/default.jade</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-6.col-md-offset-6</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            form</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-inline</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                .form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"From date"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                .form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"To date"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                .form-group</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                    .btn.btn-primary</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Update</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            .well</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                | You can track your application visitors with this URL:</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                br</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                | http://localhost:3000/track/APP1TOKN</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row.m-t-md</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Visitors</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            .well</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                | Chart goes here</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-6</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Visitors by country</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            table</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.table.table-bordered</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                thead</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    tr</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        th</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Country</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        th</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Visitors</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                tbody</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    tr</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> USA</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 100</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    tr</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Germany</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 50</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    tr</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> North Korea</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 42</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    tr</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Greenland</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 39</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    tr</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Spain</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                        td</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> 2</span></span></code>

src/views/edit_application.jade :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> layouts/default.jade</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row.m-t-md</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-6</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Application settings</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            form</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Name"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                    .btn.btn-danger</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Reset stats</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-success</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Save</span></span></code>

src/views/new_application.jade :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extends</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> layouts/default.jade</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> content</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .row.m-t-md</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .col-xs-12.col-md-6</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> New application</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            form</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Name"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                    button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-success</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Create</span></span></code>

And to make Bower-managed libraries available in our views, we need to add one more path to the server configuration:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'bower_components/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">server</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        port</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        livereload</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        directoryListing</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        open</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

As you can see, we used Jade's block extending and split our templates into one layout and many partials, so our file tree is clean and changing any of the pages will not be a hard task.

Full code of these steps

Architecture details

In our frontend application we'll use something called MVVM . That is a design pattern, kindly provided by Angular. So our views will be displaying data and transferring it to controllers (or ViewModels) , and all the logic, handling that data will be defined in controllers and services , representing Models . Actually, our models will be handled on a server-side, and services will only provide an interface to them. But that is totally another story and will be described later.

For now let's integrate Angular in our application. And we'll start, deciding how we'll split our application on the Angular layer. Pages we described above are used for these actions:

Action Resource (model)
sign in Session
sign out
sign up User
edit profile
update profile
add application Application
edit application
update application
remove application
show application
track visitor Visitor

And so we can define corresponding Angular controllers:

Url Controller
/ LandingPage
/new-session Session
/applications ListApplications
/applications/new NewApplication
/applications/:id ShowApplication
/applications/:id/edit EditApplication
/edit-account EditAccount

Angular

Angular.js is a framework by Google for making SPA s ( Single-Page Application ). SPA is a great architecture, where you have a thin backend server, providing an API to your slim frontend application. And the most interesting part here, is that you have all your application' pages in a one place, loaded once. And they are switched by a router in a user's web-browser. So all the communication with server is stripped to data manipulation requests ( creation, updating and reading data from server ) and first-time request, sending the HTML, CSS and JavaScripts to user's browser. And then, all the interactions are performed in a browser. At maximum, frontend application can request a partial or some assets ( like images ) from a web-server.

Basically, here's how SPA works:

  1. user enters a website
  2. server sends application' code (implemented in JavaScript) and HTML to user
  3. user, say, clicks on a link to change the page
  4. if application needs partial, it requests server for a HTML partial
  5. application renders a retrieved (or cached) partial in a browser

Let's start and you will see how easy it is!

Kickstarting

We'll start, adding Angular to our bower.json dependencies:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bower</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> angular</span></span></code>

Now when we have Angular inside the bower_components directory, let's add its references to our layout:

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    script</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"angular/angular.js"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Now, the only two things we need to start using Angular right away are:

  1. Angular application, defined in the JavaScript and referenced in the &#x3C;html> tag with ng-app directive
  2. Angular controller, which will contain scope with variables and functions for the page' portion

Yeah, we definitely need some clarifications about those two new words.

Theory bits

Angular defines a few kind of bricks, you may use to build an entire application:

  1. templates - dynamically changed HTML files
  2. two-way data binding , used mostly within interpolations - a mechanism for sharing dynamically changed (by either user of javascript) data between views and code
  3. controllers , holding scope - are JavaScript objects, containing variables and functions to be used in templates (functions and variables are put inside a scope, which is an argument to corresponding controller; I'll describe it later)
  4. factories (or services ) - helper objects, containing logic which is not directly related to views (displaying and retrieving data)
  5. directive - is a place, where HTML-related code is placed

On the other hand, in MVVM architecture we have three layers:

  1. Model - layer, performing manipulations on data; kind of database layer
  2. View - user interface layer
  3. ViewModel - stores data to be shown on UI or which was retrieved from UI

Accordingly to this scheme, in Angular we have the next logic structure:

  1. Model - Services
  2. Views - Templates , Directives
  3. ViewModel - Controllers

Here I did not mention two-way data binding and scopes , because first one is a part of templates and the second one is a part of controllers . And they may not be separated one from another.

Kickstarting. For real

Let's add some Angular logic into our project. We'll split our app into all those controllers and services very soon. But first, we need our application in Angular to be registered. Create a file config.js inside the src/javascripts/ directory with the following content:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStatsApp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angular</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsApp'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [  ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And point the whole layout to use that application with the ng-app directive on &#x3C;html> tag:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">doctype html</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">html</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(lang</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"en"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ng</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">app</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ourStatsApp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    head</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        block head</span></span></code>

Now when we have our app accessible by all our pages, let's create our first controller, which will handle exactly one page, the landing page. To expose our controllers, we need to make a module, consisting of controllers and add it as a dependency to our application. If you take a look at the application definition, it is also a module. The first parameter to angular.module() function is a module name, the second one is a list of dependencies.

Controllers are defined in a same way, but the dependency list for them contains module definition as the last element as well. Let's define a LandingPageCtrl controller in a src/javascripts/controllers.js file:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStatsControllers </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angular</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsControllers'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'LandingPageCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$scope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$scope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">apps </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 142</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Here we defined a module ourStatsControllers , which will contain all the controllers and a LandingPageCtrl controller, which is a module of the same name, with a single dependency - $scope and its implementation. As you can see, the $scope appears here twice - first time as a dependency name and second time as an argument to controller' definition function. That's exactly how dependency injection is made with Angular. Here we defined a scope variable for our controller too, called apps . We'll use it in just a moment.

Note the second argument: it's not required to be a list with dependencies' names first and controller implementation function, taking all those dependencies as arguments last. This is done only for the sake of minification. That's it, if you decide to minify your javascript files, you'll get a lot of errors if you will not specify dependencies' names as first list items, because most of javascript minifiers shorten your variables' names to just a few symbols, while keeping strings all the same. So if you are not minifying your javascript files, this code will work perfectly:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'LandingPageCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$scope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Instead, when minified, this controller will be transformed into something like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'LandingPageCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

And Angular will try to find a controller, factory or a service, named b . And will probably fail. But if you use "explicit" dependency injection, like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'LandingPageCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$scope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$scope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#179299;--shiki-dark:#81C8BE"> ...</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span></span></code>

then this code will be minified to something like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'LandingPageCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'$scope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">){</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span></span></code>

And then Angular will try to inject the $scope service and will succeed. Just keep this small trick in mind, when developing a real-world Angular applications.

Now we need to inject our controllers module into our application. So we just add a dependency entry inside our application declaration:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStatsApp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angular</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsApp'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsControllers'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

As we already defined the ourStatsControllers module, we don't need to provide an implementation for it.

But to make our controller work properly, we need either to declare it on frontend, making it handle static piece of a page, or make our application use different controller and view, depending on a route in a browser's address line.

The first approach is good when you use Angular for complex widgets on a page. But we need something more from our application, so we'll set up router. It'll parse URL from browser and run the corresponding controller.

Router we'll be using is ngRoute . This is a third-party plugin for Angular. And in order to use it, we need to add a Bower dependency to our project:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bower</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save-dev</span><span style="color:#40A02B;--shiki-dark:#A6D189"> angular-route</span></span></code>

Now we only need to reference it in our app definition:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStatsApp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angular</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsApp'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'ngRoute'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ourStatsControllers'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The next step is configuring our application routes, making application to "understand", which controller and which template it should run. This may be done in the same file, as the application definition:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsApp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">config</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$routeProvider'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$routeProvider</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $routeProvider</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/home'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'partials/landing-page.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'LandingPageCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            otherwise</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                redirectTo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/home'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This configuration makes our application run LandingPageCtrl when the /home page is entered. And if the URL entered is not known, application will redirect user to the /home page. All Angular routes are passed as an anchor, so saying the /home page we actually mean http://your.host/#/home . This makes browser not send requests to the server, requesting non-existent pages.

Also, note we point our application to use the partials/home.html template. But we did not tell the Angular where to render it. To fix that, we'll add a ng-view directive to the .container-fluid element of our &#x3C;body> tag, right in our layout:

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    block</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        .container-fluid</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ng-view</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Currently, when the project is built with the Gulp' build task, we have a public/home.html page, but it is not a partial - it is a standalone page, extending the layout. But what we need is to compile all our Jade templates into a public/partials directory, making them available through the /partials/partial_name.html URL. And they should not extend the layout, because then we'll end up with an incorrect HTML code.

To make the magic happen, we only need to change our build task for Gulp to build views directly to the public directory. So the src/views/index.jade file will be the main HTML page of our application, available through /index.html URL. And all the partials would be our Angular controllers' templates, available through /partials/template_name.html URLs.

Now the views part of Gulp build task should look like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/views/**/*.jade'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">jade</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And let's just extract the content of index.jade partial as it is now, all the content into a separate Angular partial, src/views/partials/home.jade .

And let's add only one small change - add only one line there:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">h1</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Currently running {{ apps }} apps</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">h1</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

Remember, we have the $scope parameter for our LandingPageCtrl controller? And that there we set the apps variable? That is it, displaying on our home page. All the other parameters, added to the $scope are available on the corresponding template, by default. You may display them with some formatting, looping through the list with ng-repeat and using them as conditionals with ng-if or ng-show . But let's go step-by-step.

Code goes here

Populating our app with stuff

For now, let's add all the other controllers to our app. Just create empty controllers according to the table from part one , using the same approach as described right above.

We'll define each controller in its own file, but all of them will be concatenated into one big application javacript file. We'll use Gulp for this purpose with its gulp-concat plugin.

Let's install it:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gulp-concat</span></span></code>

Its usage is super-easy: you just redirect the output of our CSS and JS files compiler to the concat(filename) function, providing it with a resulting filename. Like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> concat </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'gulp-concat'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/javascripts/**/*.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">babel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">concat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'all.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/javascripts'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/stylesheets/**/*.scss'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sass</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> style</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'expanded'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">concat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'all.css'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/stylesheets'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Now, the controllers. First we need to set the routes. The router configuration for our application will look just like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$routeProvider</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'landing-page.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'LandingPageCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/new-session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'new-session.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NewSessionCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/edit-account'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'edit-account.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'EditAccountCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/applications/:id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'show-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ShowApplicationCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/applications'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'list-applications.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ListApplicationsCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/applications/:id/edit'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'edit-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'EditApplicationCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/applications/new'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'new-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NewApplicationCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">otherwise</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        redirectTo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And we currently have a lot of pages with broken links. We should fix that, providing URLs to our (empty for now) controllers. Like this one:

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">a</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-primary.btn-lg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"#/sign-in"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> role</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"button"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Sign in</span></span></code>

Fix those links for all the views by yourself - that is not a complex task. All the routes are described both in the app configuration and in a table above.

Demo

See the Pen Simple web analytics. Angular injection. v1 by Artem Shoobovych ( @shybovycha ) on CodePen .

Two sides of web application. Part 3: Communication Layer urn:uuid:9c816ba1-ae4f-57e2-a7f4-2102fe0584fb 2016-02-11T00:00:00Z 2016-02-11T00:00:00Z
Funny image

Foreword

In this section we will implement the communication layer for our application. It'll handle all the requests to/from our web server. Have no worries - we will create server application in the next section!

First resource

Let's create a Session resource. Since we have no backend part, we should stub the data. We'll use Angular Services . That's easy: a service defines a function, returning, say, an object. That object will be used every time you call a service. And you may use not only objects - you may return functions, constants or literally anything from your services.

Artem Shubovych
Funny image

Foreword

In this section we will implement the communication layer for our application. It'll handle all the requests to/from our web server. Have no worries - we will create server application in the next section!

First resource

Let's create a Session resource. Since we have no backend part, we should stub the data. We'll use Angular Services . That's easy: a service defines a function, returning, say, an object. That object will be used every time you call a service. And you may use not only objects - you may return functions, constants or literally anything from your services.

We'll return an object with two methods: get(account) and create(account) . Both methods will take an object, containing user account details - email , password , and, in case of create() , name and password_confirmation , additionally. You might've guessed already: the get(account) method will log the user in and create(account) will register a new account for the user.

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Artem'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '[email protected]'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            get</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> params </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">password</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            create</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> params </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">password</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

When you inject it into your controller, you may use it via

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The thing here is that we want to keep user data somewhere to simulate a database work. So when user "signs up" , he will have his data saved in the memory not to loose it when changing a page. We'll use another service for that purpose. But contrary to our sessions service, this one will be used in the future and even barely changed.

Now, here's one more trick: we defined our Session factory in the ourStatsControllers module. Why did we do this? Why not just use ourStatsApp module? This is done mostly to keep things in one place, so everything related to controllers and UI processing is kept inside one module. Doing so we can later separate our modules into separate files and keep our main application module clean from unnecessary code (in terms of the whole application) .

To store user account data we'll use cookies. And there is a plugin for this already! It is called ngCookies . And we'll install it right now:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bower</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> angular-cookies</span></span></code>

This one's configuration is a bit more complicated. But just a bit: it needs to be added to application dependency list:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStatsApp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angular</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsApp'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'ngRoute'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ngCookies'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ourStatsControllers'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

But since we use cookies directly in controllers only, we may move the ngCookies dependency to the ourStatsControllers module:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStatsControllers </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angular</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsControllers'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'ngCookies'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ourStatsApp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> angular</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">module</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ourStatsApp'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'ngRoute'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ourStatsControllers'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Now we need to define our AccountData service. It'll also require a ngCookies dependency:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'AccountData'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$cookies'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$cookies</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            get</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $cookies</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getObject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'account'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            set</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                $cookies</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">putObject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'account'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            reset</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                $cookies</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">remove</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'account'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And we need to modify our Session service a bit:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$http'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'AccountData'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> AccountData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Artem'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '[email protected]'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            get</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> params </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">password</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(testAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            create</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> params </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">password</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(testAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And now we can implement the controller to pick up the newly added service:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'NewSessionCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$scope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'AccountData'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$scope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Session</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signIn</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signUp</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signOut</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reset</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

But here's just one small detail: we need both Session and AccountData services to perform similar actions - managing session. We can refactor our code to keep all the session management tasks in one place - Session service:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$http'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'AccountData'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> AccountData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> testAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Artem'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '[email protected]'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            get</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> params </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">password</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(testAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            create</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">account</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> params </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">email</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> account</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">password</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(testAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            reset</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reset</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Now our NewSessionCtrl could be refactored too:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'NewSessionCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$scope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$scope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Session</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signIn</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signUp</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signOut</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reset</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Looks better, huh?

So now we have our first member of our Model layer. It works with stubbed data right now, but we'll be changing that later. It is not bound to the ViewModel , because the values of our $scope.newAccount and $scope.existingAccount are constant and don't depend on the template. To change this, we need to modify our new_session.jade template:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">.row</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .col-xs-12.col-md-4.col-md-offset-1.well</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Sign up</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        form</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ng-submit</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"signUp()"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Your name"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ng-model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"newAccount.name"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"email"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Email"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ng-model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"newAccount.email"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ng-model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"newAccount.password"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password confirmation"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-primary</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Sign up</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .col-md-2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    .col-xs-12.col-md-4.well</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        h3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Sign in</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">        form</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">ng-submit</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"signIn()"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"email"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Email"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ng-model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"existingAccount.name"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                input</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-control</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> placeholder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Password"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> ng-model</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"existingAccount.password"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            fieldset</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.form-group.text-center</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">                button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">.btn.btn-success</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) Sign in</span></span></code>

Note the ng-model directive: it performs two-way data binding. It means, when user changes the value of our, say, name input, the corresponding value inside controller, namely $scope.newAccount.name , will also change. What's more, when the value of $scope.newAccount.name will be changed from the JavaScript (or, from the controller itself), the value within the input in a user's browser, will also be changed.

Now, what's about the ng-submit directive. It is added to form tags only. And it works exactly as you might've guessed: when form is submitted, the corresponding expression within that directive is called.

Making fake calls

Now that we have our stubbed signing in and up routines, we may redirect user to the right page when he signed in or up successfully. This is the job for $location service. It's available in Angular core module, ng , so we don't need to add any new module-wise dependencies. Just use it in our NewSessionCtrl :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'NewSessionCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$scope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '$location'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$scope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> $location</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Session</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signIn</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/applications'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signUp</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/applications'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signOut</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reset</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Here comes new refactoring-able piece of code: we now have our routes declared in both ourStatsApp module and ourStatsControllers . So if we decide to change, let's say, route /new-session to /login , we will need to change it in both modules. We can easily extract those URLs into a single service and use it in both ourStatsControllers and ourStatsApp modules, because everything we define in ourStatsControllers will be available in the ourStatsApp thanks to dependency injection. And since our URLs will always be the same (except, maybe, the parametrised ones) , we may define a constant instead of factory:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">constant</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Url'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        landing</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        newSession</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/new-session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        editAccount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/edit-account'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        listApplications</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/applications'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        newApplication</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/applications/new'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        showApplication</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ':id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `/applications/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        editApplication</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ':id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `/applications/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">/edit`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Application startup phases

As you can see, there are a couple of entities you can create with Angular - we've already dealt with controllers , factories , modules and constants . They all are slighty different from each other and the difference lies under Angular startup process.

When your application "starts up" or initializes, there are two kingds of methods, which are ran first: config and run . They are user-defined and your application can have more than just one of those. Those methods define the initialization behaviour of your application. They both can deal with dependency injection. But their run order is different: config blocks are executed first, at the very beginning of the whole application initialization process. Thus you can inject only providers ( $routeProvider for instance) and constants into config blocks. Whilst run blocks can only handle instances (for example, $scope ) and constants .

Since we have our routes defined at the config stage, we need to use constant to name our routes. And then use them like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsApp</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">config</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#40A02B;--shiki-dark:#A6D189">'$routeProvider'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Url'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$routeProvider</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $routeProvider</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">landing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'landing-page.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'LandingPageCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newSession</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'new-session.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NewSessionCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">editAccount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'edit-account.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'EditAccountCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">listApplications</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'list-applications.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ListApplicationsCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newApplication</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'new-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NewApplicationCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">editApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'edit-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'EditApplicationCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">showApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'show-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ShowApplicationCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">otherwise</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    redirectTo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">landing</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsControllers</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">controller</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'NewSessionCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'$scope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '$location'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Url'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$scope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> $location</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Session</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signIn</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">existingAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                $location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">listApplications)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signUp</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newAccount)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                $location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">listApplications)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $scope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">signOut</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">reset</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                $location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">landing)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ])</span></span></code>

To show the difference in practice, let's add the authentication verification. We now have our stubbed account and session management service, so why not? Angular provides us with two options:

  1. the resolve attribute for the $routeProvider.when() method
  2. the $routeChangeStart event

The first approach is nice, but since we set up routes in the config section, we are not allowed to use services. And that is the problem, because we've got our Session service, handling the tasks we need. And one more drawback of this method: one should set it for each route, which requires verification:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> verifyAuthentication</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsApp</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">config</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#40A02B;--shiki-dark:#A6D189">'$routeProvider'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Url'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$routeProvider</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $routeProvider</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">landing</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'landing-page.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'LandingPageCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newSession</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'new-session.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NewSessionCtrl'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">editAccount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'edit-account.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'EditAccountCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    resolve</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> verifyAuthentication</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">listApplications</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'list-applications.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ListApplicationsCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    resolve</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> verifyAuthentication</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newApplication</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'new-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NewApplicationCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    resolve</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> verifyAuthentication</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">editApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'edit-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'EditApplicationCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    resolve</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> verifyAuthentication</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">when</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">showApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'show-application.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    controller</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ShowApplicationCtrl'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    resolve</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> verifyAuthentication</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">otherwise</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    redirectTo</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">landing</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Handling $routeChangeStart event suits us, and what's more interesting: it shows the use of run section. But as a drawback to this, we'll need the list of routes, which need to be checked. So I modified the definition of Url constant like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsApp</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">constant</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Url'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> urls </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            landing</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            newSession</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/new-session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            editAccount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/edit-account'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            listApplications</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/applications'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            newApplication</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '/applications/new'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            showApplication</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ':id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `/applications/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            editApplication</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ':id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `/applications/</span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">/edit`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        urls</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">authRequired </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            urls</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">editAccount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            urls</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">listApplications</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            urls</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newApplication</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            urls</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">showApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            urls</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">editApplication</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> urls</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)())</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

A bit tricky, does not it? And here's the handler for the $routeChangeStart event:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsApp</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">([</span><span style="color:#40A02B;--shiki-dark:#A6D189">'$rootScope'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '$location'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Session'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'AccountData'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Url'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$rootScope</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> $location</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Session</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> AccountData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> Url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $rootScope</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$on</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'$routeChangeStart'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> current</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> next</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // check if user is authenticated for selected URLs only</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // first, try to restore his session</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // if this failed because user has no AccountData cookie - redirect him to newSession page</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">authRequired</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">indexOf</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">($location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()) </span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Session</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">() </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;&#x26;</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">AccountData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    $location</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newSession)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Rocking on

Other services and controllers are much like those we already have, so I'll just put in the code in the end of the page. The interesting thing here is the MockData service that I've used to keep data, used while we have no server side.

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsApp</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">constant</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'MockData'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        account</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Artem'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            email</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '[email protected]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            password</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'abc123'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        applications</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'App #1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                token</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'APP1TOK'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                stats</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    byCountry</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Poland'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> amount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'USA'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> amount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 190</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Algeria'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> amount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'App #2'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                token</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'APP2TOK'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                stats</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    byCountry</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Vietnam'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> amount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'New Zeland'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> amount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 19</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'USA'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> amount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                id</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'App #3'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                token</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'APP3TOK'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                stats</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    byCountry</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'USA'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> amount</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 95</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ourStatsApp</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">factory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'Application'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189">'$http'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'MockData'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">$http</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> MockData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            create</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // send data to the server and check if response status == 200; return application (arg)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            get</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> fromDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> toDate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // fromDate and toDate are used for stats filtering</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // send data to the server and return response</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MockData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">applications[id]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            update</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // send data to the server and check if response status == 200; return application (arg)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            },</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            all</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // send request to the server and return the response</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MockData</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">applications</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And here's the demo of what we've done up until now:

See the Pen Simple web analytics. Communication layer. v2 by Artem Shoobovych ( @shybovycha ) on CodePen .

Irrlicht Newton GD tutorial: finishing the first scene urn:uuid:34802d5d-9e04-5c85-a55d-57ed28362967 2015-12-16T00:00:00Z 2015-12-16T00:00:00Z

If you remember, we ended our coding excercises at place, where we almost created our first Newtonian body, but we did not actually have enough models.

We discussed collision shapes a bit. So let's create one for our brand new model!

We have a nice ramp to work with. But how we can reconstruct the same shape in the terms of Newton? Newton offers a set of collision shapes for us:

  • Sphere

    Sphere
  • Box

    Box
  • Cone

    Cone
  • Capsule

    Capsule
  • Cylinder

    Cylinder
  • Chamfer Cylinder

    Chamfer Cylinder
  • Convex Hull

    Convex Hull
  • Trimesh

    Trimesh

Obviously, not sphere, cone, capsule, nor cylinder make sense for us. We could use box shape, but then we simply ignore our inner faces (inside walls):

Box collision shape for our ramp

A bit better, but still the same situation with convex hull shape:

Convex hull collision shape for our ramp

Generally, the way we create our Newtonian body is:

  1. create collision shape
  2. create blank Newtonian body
  3. set body properties like collision shape, mass, inertia parameters, etc.
  4. store the pointer to the graphical entity for that body in the userData property

And then Newton Game Dynamics will take your body into account when processing other objects in the NewtonWorld .

Artem Shubovych

If you remember, we ended our coding excercises at place, where we almost created our first Newtonian body, but we did not actually have enough models.

We discussed collision shapes a bit. So let's create one for our brand new model!

We have a nice ramp to work with. But how we can reconstruct the same shape in the terms of Newton? Newton offers a set of collision shapes for us:

  • Sphere

    Sphere
  • Box

    Box
  • Cone

    Cone
  • Capsule

    Capsule
  • Cylinder

    Cylinder
  • Chamfer Cylinder

    Chamfer Cylinder
  • Convex Hull

    Convex Hull
  • Trimesh

    Trimesh

Obviously, not sphere, cone, capsule, nor cylinder make sense for us. We could use box shape, but then we simply ignore our inner faces (inside walls):

Box collision shape for our ramp

A bit better, but still the same situation with convex hull shape:

Convex hull collision shape for our ramp

Generally, the way we create our Newtonian body is:

  1. create collision shape
  2. create blank Newtonian body
  3. set body properties like collision shape, mass, inertia parameters, etc.
  4. store the pointer to the graphical entity for that body in the userData property

And then Newton Game Dynamics will take your body into account when processing other objects in the NewtonWorld .

Tree mesh collision shape

So we gonna use the triangle mesh shape. What we gonna do is loop through all the triangles of our mesh and build its copy, but in the world of "physic" bodies.

To loop through all the triangles, we need to take each 3 edges of our mesh and the corresponding vertices (because each edge is represented by two its vertices - their indexes in the list of vertices) and create Newtonian triangle. Irrlicht stores vertices in one of three formats:

  1. plain vertex, represented by its three coordinates; the irr::video::S3DVertex class in Irrlicht
  2. vertex with texture coordinates; irr::video::S3DVertex2TCoords class
  3. vertex with its tangent information; irr::video::S3DVertexTangents class

All those are represented by irr::video::S3DVertex class or its children. Moreover, we do not need nothing but the information on vertex' coordinates in our case, so we may use only the base class' properties.

The code, creating trimesh collision shape is quite simple and straightforward:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createTrimeshShape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IMeshBuffer</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">meshBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NewtonCollision</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">treeCollision</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">                                     irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">vector3df</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> scale</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df vArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">S3DVertex </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mb_vertices </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">S3DVertex </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> meshBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getVertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    u16 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mb_indices </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> meshBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getIndices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> meshBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getIndexCount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> j </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v1i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mb_indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">j </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v2i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mb_indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">j </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v3i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mb_indices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">j </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mb_vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v1i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mb_vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v2i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        vArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mb_vertices</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v3i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Pos </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        NewtonTreeCollisionAddFace</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">treeCollision</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

We take the edges (indices) , find their vertices, create a triangle - and we're done! You may have noticed, we do not actually create the collision shape here - we take it as an argument for our function. You will see why this is done that way in a moment.

Now it's body's turn! But we need to extend our Entity class with the NewtonBody field so that we can seamlesly integrate it to our engine:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewtonBody </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    Entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ISceneNode</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    Entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ISceneNode</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NewtonBody</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ISceneNode</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    NewtonBody</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">NewtonBody</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        mBody </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

And now we are ready to set our NewtonBody :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createMeshBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Entity </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entity </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entities</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IMeshSceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IMeshSceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewtonCollision </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> NewtonCreateTreeCollision</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonTreeCollisionBeginBuild</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IMesh </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mesh </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getMesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getMeshBufferCount</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IMeshBuffer </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mb </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getMeshBuffer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        createTrimeshShape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getScale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonTreeCollisionEndBuild</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dMatrix origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonCollisionGetMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewtonBody </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> NewtonCreateDynamicBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dVector inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonConvexCollisionCalculateInertialMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetMassMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetCentreOfMass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonDestroyCollision</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetTransformCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetForceAndTorqueCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> applyForceAndTorqueCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetUserData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonInvalidateCache</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

There is an interesting piece here, though: we used recursion to create collision shape... But if you remember, we did not create collision shape with our createTrimeshShape method - all we do in that method is that we add new triangles to the existing shape. That's because meshes in Irrlicht are stored as a tree structure - they may have sub-meshes, which are still parts of the whole mesh. And they can have their sub-meshes too. So we created a blank collision shape and fill it with new parts of the mesh.

Doing it that way prevents us from overcomplicating the task and building a composite mesh, made of a set of trimeshes. That would be really hard to calculate in real-time! And our really simple scene would work with the speed of 5x5 battle in Unreal Tournament 3...

Looking back to our list, we should now fill out all the fields for our NewtonBody . And since we are making the static model, we will set its mass to zero. This is enough for Newton to treat our body as the static one. I placed the other code to show the other fields, we need to fill in case we have a "usual" body.

So the other fields of NewtonBody are:

  1. massMatrix , which determines how the mass is spread along the body
  2. transformCallback and forceAndTorqueCallback are two mandatory fields, required by Newton
  3. userData , which will hold the pointer to the whole entity

massMatrix could be calculated automatically from the collision shape, like in our case. Without digging much into details, we will simply set it so the mass of our body is distributed uniformely.

transformCallback is the function, which will be called for our body each time it changes its position due to the interaction with other bodies inside NewtonWorld .

forceAndTorqueCallback is the function, which applies forces and torques to our body. This is a bit tricky, but you need to keep track of each force and torque by yourself and then apply them in a way that they summ up and create the final force, influencing the body. We will talk about it later, when we will deal with impulses.

So, the transformCallback :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> transformCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NewtonBody</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> dFloat</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">matrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> threadIndex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Entity </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entity </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Entity </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> NewtonBodyGetUserData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#179299;--shiki-dark:#81C8BE">!</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">matrix4 transform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    transform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setM</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">matrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">transform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTranslation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">transform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotationDegrees</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Nothing tricky here.

To put everything in place, let's add a sphere to our scene. The process is totally same, except of the collision shape creation - in case of primitives like box, sphere or cylinder, it is much more easy than with trimeshes - you do not need to loop through any indices or vertices - just set shape params like dimensions or radius. And body creation process is totally same.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createSphereNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> textureFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addSphereSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialFlag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMF_LIGHTING</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    entities</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">NewtonCollision</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createSphereCollisionShape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ISceneNode</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> radius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dQuaternion </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dVector </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dMatrix </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shapeId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> NewtonCreateSphere</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shapeId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createSphereBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> radius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> mass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Entity </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">entity </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entities</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dQuaternion </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dVector </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dMatrix </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">q</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shapeId </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewtonCollision </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> NewtonCreateSphere</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> radius</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shapeId</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dMatrix origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonCollisionGetMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    NewtonBody </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> NewtonCreateDynamicBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dVector inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonConvexCollisionCalculateInertialMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetMassMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inertia</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">m_z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetCentreOfMass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">origin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">][</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonDestroyCollision</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">shape</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetTransformCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> transformCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetForceAndTorqueCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> applyForceAndTorqueCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetUserData</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonInvalidateCache</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    entity</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setBody</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Have no fear about code duplication - we will remove it later. When you are done, you should get picture like this one:

First completed dynamic scene

Congrats! That's our first completed dynamic scene!

Irrlicht Newton GD tutorial: making simple level with Blender urn:uuid:22ac9892-e905-5b35-bcdb-fe51918ef285 2015-12-15T00:00:00Z 2015-12-15T00:00:00Z

In this section we will have short but powerful introduction to Blender. We will cover just enough of model creation basics, you will need to create most of simple projects.

No, we will not cover animation, shaders or modificators here, but just enough minimum to create this ramp floor for our tutorial:

The desired result

You will find lot of keyboard shortcuts here. And this is one of the most awesome features of Blender - you can work without menus or panels! Everything you need can be done with keyboard!

So let's dive in Blender now!

Artem Shubovych

In this section we will have short but powerful introduction to Blender. We will cover just enough of model creation basics, you will need to create most of simple projects.

No, we will not cover animation, shaders or modificators here, but just enough minimum to create this ramp floor for our tutorial:

The desired result

You will find lot of keyboard shortcuts here. And this is one of the most awesome features of Blender - you can work without menus or panels! Everything you need can be done with keyboard!

So let's dive in Blender now!

Welcome to Belnder

When you open Blender, you will see some pretty image, made with Belnder, version information, some useful links and recent files

Blender

To close this window, simply click outside it. You will then see your workspace with the Default window layout (we will learn about them later) . Workspace contains a few kickstarting items:

  • camera
  • light
  • cube
Workspace

You may be confused of the last one, but you will see shortly that so many cool things could be done starting with plain cube and modifying it. Oh, and about modifying: let's switch to the Edit mode , hitting the Tab key:

Edit mode

You can exit it hitting Tab again. In the edit mode you can manipulate mesh' edges , vertices or faces . To switch between these, use three buttons on the screen's bottom:

Switching between edges, faces and vertices in edit mode

Let's choose the faces editing mode. Unlike other 3D editors, in Blender selection is done with the Right mouse button . Select one face of the cube:

Selecting items in blender

You may have noticed that the axis arrows have moved in the selected face's place. These are used to manipulate selected elements. Also, they show the orientation of the selected element. You can move the selected element by simply dragging one of the arrows. Selected element will be moved along the selected axis only:

Moving selected elements

The same operation, movement, could be performed hitting the G key. You can move other elements, too - this will change the form of our cube:

Moving edges

Now let's try something more complex. See the Tools panel on your left?

Tools panel

Select a face in a face editing mode and click Extrude (or hit the E key). Your face will be extruded and you will be able to move it freely. But usually, designers move elements along some axis - this makes models more accurate. To fix the movement axis, just hit its letter while being in the extruding mode - X , Y or Z :

Extruding faces

Interesting fact: you may extrude both vertices and edges too.

Now, let's use even more advanced operation, which is oftenly described later in tutorials on 3D modelling. Choose the Loop cut and slice operation from the Tools panel - you will see nothing. Until you move your cursor over your model. Depending on the edge, cursor is closer to, you will see purple rectangle, looping through your model:

Loop cut

When you click the Left mouse button , you will move to the next part of this operation - slicing . Just place the new edges where you want:

Slicing the loop cut

Now let's create walls for our "ramp". Create a few loop cuts alongside the ramp and we will start extruding:

Extruding one wall

Or maybe just moving faces?..

Moving vs extruding

No, that's definitely not what we want! We want walls, not a new ramp! Hmmm... But if we will extrude walls one-by-one, it will be inaccurate... Hold the Shift key and right-click the two neighbour walls:

Multiple selection

Now we will work with three elements in the same way. Hit the E key and then - Z and extrude all three walls at the same time up:

Simultaneous extrusion

Now we need two more walls to prevent our hero (the ball, if you recall from the previous part) from falling aside. Select two edges at the corner of our ramp and hit the W key. You will see the context menu like this:

Editing context menu

Click the Subdivide item, and the selected edges will be connected right in the middle:

Subdivision for two edges

You can perform that operation on faces - that is oftenly handy. Now, if you undo your changes with usual Ctrl + Z (or Command + Z on Mac) and try to perform the same operation on four opposite edges, you will see there is a redundant (in our case) edge:

4-th subdivision

You can remove it by selecting that edge, hitting X and selecting Dissolve edges . If you choose the Delete edge - you will loose the neighbour faces, which were made of that edge.

Delete or dissolve?

So in the end we need to have two edges on the same line:

The needed edges

Now, switch to the Ortho View , choosing one from the View menu at the bottom of the screen, or hitting the Num 5 key:

View menu

Your workspace now should look different:

Ortho view

Using the View menu, you may switch between different views, perpendicular to your model.

Top view Right view

Switching between different views will not clear the selection. And this is awesome! So if you try to move the selected edges in the Right Ortho View , you will move both of them:

Selection persistence

Yeeks... They move just along the Y axis, but not along the edge. But Blender easily handles that - you need to switch between coordinate system using the corresponding menu at the bottom of your screen:

Coordinate system

Use the Normal one and you will see the arrows at the selected edges changed:

Normal coordinate system

Now movement is done along the edge, just as we need:

Moving with Normal coordinate system

Try moving (yes, moving, not extruding) our edges up - they will move along the normal:

Moving edges in Right Ortho view

But if you click the mouse wheel and rotate camera , or even if you switch to the Top Ortho view, you will notice that our walls have different width:

Whoops...

So we need to make one wall thinner. But we should not forget about other edges - ones, which will make another wall for us. Undoing now is not an option... We need to move the edges. But if you move only those visible at the Top Ortho view, you will forget about the ones at the bottom and screw the model. And selecting all those edges one-by-one is not an option too...

Selecting many edges manually is a pain...

Moreover, we do not see those edges at the bottom! This is easy to fix, though: see the small button with rectangles near the vertex/edge/face switcher?

'Limit selection to visible' switcher

Click it and you will be able to select bottom edges without the need to rotate the camera. And now we will try the circle-selection tool, which will come to help you when you need to select many elements at a time. Hit the C key and you will see the circle in a workspace. Try dragging it ( left-click the mouse and drag ) over the edges we need:

Circle selection

Hmmm... It's way too much... Now, hold the Shift key and drag the circle over the neighbour, redundant ones:

Unselecting elements

Now we can switch back to the Top Ortho View and successfully move our edges:

Making walls thinner

Now that we have our walls precisely set up, we can extrude the last two walls. Select the Normal coordinate system and perform the extrusion along the Z axis:

Extruding last two walls

Now we will scale our model a few times. Staying in the Edit mode , select all the faces with the A key:

Selecting everything

And hit the S key and start entering scale factor number. That's right, just press, say, 5 :

Entering factor while scaling

You can correct what you entered using the Backspace key. You can do the same thing while moving or rotating elements. This is useful when you need to make operation really precise. But you still can use your mouse, of course.

Hint: if you scaled your model outside the Edit mode , you may find your scale, translation or rotation different from identity values ( 1, 1, 1 for scale or 0, 0, 0 for position/rotation). This may cause different bugs while exporting models. To fix this, you need to select your model in the Object mode , hit the Ctrl + A and select Apply Scale (or whatever you need to fix) from the pop-up menu.

Applying scale

Texturing our model

Now we need to paint our model to have something more beautiful in our application than just pitch black... stuff...

Adding textures to a model in Blender is extremely easy - you just select your model, switch to the Texture tab on the right panel and click New button:

Creating a texture

Then you pass in some params like texture size, the background color and image name - and you are done!

New texture params

But that will only add a blank texture. And then you will need to paint it as you wish. But painting a texture requires your model to have vertices, synchronized with your texture. So each vertex will know where it lays both in 3D space and on the texture image. This assignment process is called Texture unwrapping or UV mapping (because texture coordinates are usually called u and v instead of x and y , since those are already involved to describe vertex' position) . And this process requires one thing from you: you need to specify, where Blender should "cut" your model. This is quite simple task, but this will result on how the texture will look like and how easy it will be to paint.

So, go to the Edit mode and select a few loops of edges:

Selecting seam edges Selecting seam edges

Now, on the left panel, switch to the Shading/UVs tab and click the Mark Seam button:

Shading/UVs tab

This will mark the selected edges as seams to "cut" your model along. Have no fear, your model will not be actually cut - it will be used for maths only.

Then, on the same panel click the Unwrap button and select the first unwrapping method on the list:

Unwrapping method

Again, no effect you will see now. To see something, switch the window layout at the top menu to UV Editing :

Layout switcher Layouts available

You will see two windows - on your left there will be UV/image editor and on your right there will be the 3D view . And again, nothing interesting here... But I am not fooling with you - it's only how Blender works... To see something marvelous, select everything on the 3D view :

UV-Mapped model

You will see some lines on your left. That's what you have selected, mapped onto image plane. But there is no actual image in the UV/Image editor for now. To add one, just click the New button on the bottom menu of the UV/Image editor or select an existing one:

Selecting background image for UV mapping

This will not change the image itself. The image will be the background for our image editor window, nothing more. To start making miracles, go to the Texture Paint mode in the 3D view :

Texture Paint mode

And your model will change its look...

Pinky!

What is this pink monster?! Well, on the left panel of our 3D View there's a message, saying the texture slot is missing and proposing to create one... Let's do this...

Texture slot creation

Now we are able to paint our model! See, how awesome it is: you have a brush tool activated. Brush has three params:

  1. Color - this could be changed with the color circle below
  2. Radius
  3. Pressure , or Alpha

Radius could be changed by pressing the F key and moving mouse cursor:

Brush radius changing

Pressure could be changed by pressing Shift + F and doing the same:

Brush pressure changing

And you can just pain like in... Microsoft Paint!

Just paint!!!

But if you look into the UV/Image editor , you will see... nothing! Again! 'the hell?!

WTF?!

That is just misunderstanging - you were painting on the other image instead of the selected one:

Choosing image for UV/Image editor

We created a new one, when created a texture slot...

To start drawing in the UV/Image editor instead of 3D View , you just need to switch its mode to Paint at the bottom menu:

Painting in the UV/Image editor

Okay, so far so good. We are able to paint our model. But there's one interesting thing: if you try to draw a straight line - you may face situation, when line is straight in the image but is curved on the model:

UV mapping mistakes UV mapping mistakes

But that's happening not everywhere - only on certain faces/edges:

Mistakes are only on certain faces

Well, that's because of UV mapping is not precise enough. If you switch to the View mode in the UV/Image editor and to the Edit mode in the 3D View , and select all the model, you will see the points in the image editor, you may drag:

Control points in the image editor

Try selecting them with Right mouse button and moving them with G :

Selecting control points Moving control points

Yes, now texture looks creepy, but lines are almost straight:

Fixing UV mapping errors manually Fixing UV mapping errors manually

Exporting our model

When you finish painting your texture, the last thing we need to do is to export our model to the format, understandable by Irrlicht. For good, both Blender and Irrlicht support many different formats:

Blender exporting

Blender's file dialogs look differently, but have very intuitive interface:

Blender file dialog

If you do not see the needed format in Blender - you just need to turn on a corresponding plugin:

Blender settings menu Blender settings menu

After exporting our model to, say, 3DS format, take a look at the directory you have exported your model to:

No textures!

Where are the textures? Relax, they are in the UV/Image editor , yet unsaved. You can save the modified image with the Image -> Save menu at the bottom of UV/Image Editor :

Saving image from UV/Image Editor

Now we have everything we need for our Newtonian sample!

Next chapter

End-to-end testing with WebdriverIO urn:uuid:d00b50a2-7bed-5d24-9fea-f8aeb9a2a534 2015-11-26T00:00:00Z 2015-11-26T00:00:00Z

Small intro

Have you ever heard about end-to-end testing? Or maybe about testing automation? Those of you who had, may now be imaging Selenium. That's right, in most of cases you will need to run Selenium Server and use Selenium Webdriver in your tests. Those come handy to run a standalone browser window, with no caches, filled-in fields or cookies and perform some operations in it.

In this article I will tell you my story of writing E2E tests for Angular webapp.

A brief of history

In my case, we first tried to use Protractor with Chai.js . That time we ended up with almost unsupportable bunch of code, succeeding in 100% of runs.

Next time we eliminated Chai and reworked all our tests to use Protractor only. So the code became more clear (I did not like the syntax, but it worked...) , but after upgrading libraries (including Protractor) , the ratio of successfull test runs decreased to just 40%.

We worked for two days, trying to fix those tests. And that's how webdriverio came to our project.

And here's a short tutorial on how to implement E2E tests with webdriverio in a sample project.

Artem Shubovych

Small intro

Have you ever heard about end-to-end testing? Or maybe about testing automation? Those of you who had, may now be imaging Selenium. That's right, in most of cases you will need to run Selenium Server and use Selenium Webdriver in your tests. Those come handy to run a standalone browser window, with no caches, filled-in fields or cookies and perform some operations in it.

In this article I will tell you my story of writing E2E tests for Angular webapp.

A brief of history

In my case, we first tried to use Protractor with Chai.js . That time we ended up with almost unsupportable bunch of code, succeeding in 100% of runs.

Next time we eliminated Chai and reworked all our tests to use Protractor only. So the code became more clear (I did not like the syntax, but it worked...) , but after upgrading libraries (including Protractor) , the ratio of successfull test runs decreased to just 40%.

We worked for two days, trying to fix those tests. And that's how webdriverio came to our project.

And here's a short tutorial on how to implement E2E tests with webdriverio in a sample project.

The requirements

Before we start, we need to initialize an NPM project:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> init</span></span></code>

We barely want to manage Selenium versions by ourselves. When it comes to continuous integration, that is not an option. So we'd better find a way of downloading the needed Selenium version automatically. And writing a short script is somehow a bad idea - there is an NPM module for that task already:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> selenium-standalone</span></span></code>

After installing that module, you may manage and run your Selenium with

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">./node_modules/selenium-standalone/bin/selenium-standalone</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">./node_modules/selenium-standalone/bin/selenium-standalone</span><span style="color:#40A02B;--shiki-dark:#A6D189"> start</span></span></code>

Now, in all our tests we will be using using Jasmine , since it allows to create a beautiful code, which is easy to support (if you need the maximum help from your customer - consider using Cucumber and BDD approach - I will cover this topic in one of my future posts). So we need to add Jasmine dependency to our project:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> jasmine</span></span></code>

To initialize bare Jasmine-ready project you may use Jasmine itself:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">./node_modules/jasmine/bin/jasmine.js</span><span style="color:#40A02B;--shiki-dark:#A6D189"> init</span></span></code>

This will create this directory structure for you:

<code>.
├── package.json
└── spec
    ├── helpers
    └── support
        ├── config.json
        └── jasmine.json
</code>

So now you may place your tests in the spec directory, on any level. Just remember to name your test files with the spec postfix (for ex. spec/feature1_spec.js or tests/spec/Feature1spec.js ). To change that lowercase spec postfix, specify which files Jasmine should look for in the spec/support/jasmine.json file, using the option spec_files . For example, you can make it look for both *_spec and *Spec (underscore and camel case file naming) postfixes:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">spec_dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "spec"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">spec_files</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "features/**/*[sS]pec.js"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "**/*_spec.js"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "**/*_Spec.js"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The spec_dir option specifies the directory, where the test files are located. And the spec_files option is what we are mostly interested in: it tells Jasmine the pattern, it should use to check if a file (inside the #{spec_dir} directory) is a test file or not. For example, the first value, "features/**/*[sS]pec.js" , tells that any file, whose path is spec/features/{any directory nesting depth}/*Spec.js as well as any file with a path spec/features/{any directory nesting depth}/*spec.js is a file, containing a test definition.

The last, but not least, we need the webdriverio itself:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> webdriverio</span></span></code>

And now we are ready to make some code!

Preparation

First of all, we need to initialize the Selenium client. Generally speaking, it's a special browser instance, which will be used for our tests only and when all the tests are done - it will be closed automatically. This browser (or a client) provides a programmable interface, e.g. executes commands we ask it to execute. The commands allow, for example, to manipulate the currently opened document (just like you used to do with javascript in the developer tools in your browser) - find an element, click it, retrieve its computed styles, etc. It also allows to manipulate the browser window itself - open a new tab, get and set its properties like width, height, position and many others.

So we really need that client for our tests - that's the core! And we need that to run all our tests (we don't want to run a new browser instance for each separate test case, right?). So we can put all the code, initializing Selenium client in a helper script and make Jasmine run it before all (again, not each, but all - I'll explain why this is essential in a moment) tests. Let's define this in the spec/helpers/settings.js file:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> webdriverio </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'webdriverio'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timeout </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> config </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">  "desiredCapabilities"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "browserName"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "chrome"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "host"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "localhost"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "port"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9876</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  },</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">  "baseUrl"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "http://localhost"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">jasmine</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DEFAULT_TIMEOUT_INTERVAL</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timeout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">beforeAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">done</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">client </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> webdriverio</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">remote</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(config)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">init</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">url</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(done)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">afterAll</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">done</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">    this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">client</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(done)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic">exports</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">webdriverio </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> webdriverio</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic">exports</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">config </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> config</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic">exports</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timeout </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timeout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic">exports</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">baseUrl </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> config</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">baseUrl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This code does three simple, but really important things:

  1. it sets up the webdriverio (which is an enhanced wrapper for Selenium client) for all the tests , opens browser (configured by the browserName option) window and navigates to the page, defined in the baseUrl option
  2. makes Jasmine wait a bit longer for each assertion in the tests, before marking it as failed on timeout (when Jasmine has timed out, waiting for an assertion)
  3. makes webdriverio client instance available in any test through the this.client member (where this means the test instance)

See, this code is run once, previous to all the tests, found by Jasmine. This is defined by the beforeAll() call. We could use the beforeEach() function instead, but since opening a new browser (Selenium client) instance is a time-consuming task, it's better to do it once and then just operate on an existing instance, opening new tabs when necessary. Thus is why we are using beforeAll() for all the tests in the scope .

Here I've mentioned another essential thing, the test scope . Test scope is the current set of tests. It could be defined by the describe("description", function () { /* test code */ }) function call. But since we have no describe() calls before the beforeAll and afterAll calls, Jasmine assumes we want to use those functions for all the known tests. But if you use the beforeAll inside the describe() block, then this function ( beforeAll() ) will be run before all the tests, defined inside that describe() block .

First scenario

Assume our application is a simple webshop - it has three pages: /#/products , /#/billing-details and /#/order-summary . Rather simple webshop:

And here is our first scenario: user selects the iPhone, clicks "Buy" , fills in his billing details and waits for his brand-new iPhone to come.

In terms of BDD it could be described in a scenario like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">Feature</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Placing an order</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    Scenario</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Ordering a single product</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        Given </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a webshop page</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            And </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a guest user</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        When </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">the user selects the </span><span style="color:#40A02B;--shiki-dark:#A6D189">"iPhone"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> product</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            And </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">clicks the </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Buy"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            And </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fills out the billing details correctly</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            And </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">clicks the </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Submit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> button</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        Then </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">the </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Billing successfull"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> page is shown</span></span></code>

This scenario is great for the customer. And it's awesome if the customer is able to provide developer(-s) with a number of such scenarios. But our test will be more kind of "developer-friendly".

Let's create a specs/ordering_a_single_product_spec.js file:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> settings </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'../helpers/settings.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'buying iPhone'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'when user selects iPhone'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'he gets redirected to the billing-details page'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">done</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">client</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">waitForExist</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.title*=iPhone 6 White'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> settings</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timeout)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">element</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.title*=iPhone 6 White'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">element</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'..'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">click</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button*=Buy'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">waitForExist</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button*=Check out'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> settings</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timeout)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">url</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">err</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                    expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(res</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/\/</span><span style="color:#40A02B;--shiki-dark:#A6D189">#</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\/</span><span style="color:#40A02B;--shiki-dark:#A6D189">billing-details</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">                .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(done)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Let's run our test: first, start your webserver to handle the webshop; then run a Selenium instance and at last, start ./node_modules/jasmine/bin/jasmine.js .

In this test case we do the following things:

  1. wait untill all the products are loaded ( waitForExist('.title*=iPhone 6 White', settings.timeout) )
  2. select parent element for iPhone 6 White product ( element('.title*=iPhone 6 White').element('..') )
  3. click on the Buy button within that product' container ( click('button*=Buy') )
  4. wait until the Create account button is shown, signalizing we have been redirected to the next page
  5. get page' URL and make an assertion to check if we have been redirected to the correct page

When we have done everything we need in our test case, we call the done callback to notify Jasmine we have finished our test. This is how asynchronous tests are made in Jasmine - you define the test with it(...) , providing it with a callback. And when you finish all the asynchronous things in your test, you just call that callback so Jasmine could switch to the next test.

What's interesting, Jasmine runs test in the order they are defined. So you may assume that everything you did in previous test cases defines your current state. For example, after our test case, namely 'when user selects iPhone he gets redirected to the billing-details page' , we stay on the page we finished shortly.

Given that, we will not add additional checks or waitForExist() s to get to the next steps.

Dealing with forms

The next step is filling out billing details:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'when user provides his billing details'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'he gets redirected to the order-summary page'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">done</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            firstName</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Test'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            lastName</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'User'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            country</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'United Kingdom'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            city</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'London'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            address</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '221B, Baker Street'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            zipCode</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '12345'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            phone</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '9998882245'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">client</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'[name="firstName"]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">firstName)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'[name="lastName"]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lastName)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'[name="address"]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">address)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'[name="country"]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">country)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'[name="city"]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">city)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'[name="zipCode"]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">zipCode)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setValue</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'[name="phone"]'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> billing</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">phone)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">click</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'button*=Check out'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">waitForExist</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'h2*=Order summary'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> settings</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">timeout)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">url</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">err</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> url</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(url</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toMatch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/\/</span><span style="color:#40A02B;--shiki-dark:#A6D189">#</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\/</span><span style="color:#40A02B;--shiki-dark:#A6D189">order-summary</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">$</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(done)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

The new thing here is how we fill out input fields with webdriverio - using the setValue() method.

Advanced element lookup

The last page we need to check is order-summary . Here we want to check if the order total is exactly the same, as our iPhone' price. But this is where things got tricky: we have two different rows with the same value. How do we check if we are looking at the correct one?

We will use XPath to get to the correct element:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">describe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'order summary page'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    it</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'contains correct order total'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">done</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">client</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isVisible</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'//div[contains(@class, "row") and contains(., "iPhone 6 White") and contains(., "$450.00") and ancestor-or-self::div[@ng-repeat]]'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">visibility</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(visibility)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toBe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isVisible</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'//div[contains(@class, "row") and descendant::div[contains(., "Total:")] and contains(., "$300.00") and not(contains(@class, "ng-scope"))]'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">then</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">visibility</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                expect</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(visibility)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toBe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">            .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(done)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Seems complicated, doesn't it?.. But it's not that hard. We used XPath instead of usual selectors to find the element needed. And here's how one could read it:

say, we have this XPath: //div[contains(@class, "row") and contains(., "iPhone 6 White") and contains(., "$450.00") and ancestor-or-self::div[@ng-repeat]] .

This could be split into three parts:

  1. path to the element, // - it tells browser's engine to look for this element everywhere, independently on its parent
  2. element tag, div ; it could be "any" selector, * , but we precised our search
  3. element attributes' matchers, or everything in square brackets

Let's take a closer look on those - they are really interesting ones:

  1. first we have contains(@class, "row") ; it tells engine to look for an element, whose class attribute contains (or "partially matches" if you wish) row string
  2. now we have contains(., "iPhone 6 White") ; it looks for text content inside tag; including its children
  3. speaking of children, we've also got a parent matcher, ancestor-or-self::div[@ng-repeat] , which looks for &#x3C;div> element with ng-repeat attribute in the current element or any of its parents
  4. you may noticed a concatenation of all those matchers with and keyword

Wrapping up

So that was a really short example on how to use Jasmine, webdriverio and how to create end-to-end tests. As promised, I will cover the BDD testing and Cucumber in some of my future posts.

References

Try reading more on XPath on w3schools .

Webdriverio API you may find on its docs page .

Webshop application, used in this article is available on GitHub .

Loooong lists with Clojure urn:uuid:6ad426bf-3d77-5970-9608-562ffd905cdc 2015-10-16T00:00:00Z 2015-10-16T00:00:00Z

Whaaaaat?

These days I was given a reeeeally interesting homework at the university. I was given a set of MD5 hashes, calculated from single words (taken from Libre Office' dictionaries) with a given sault. And the task was to find all those words.

So, the first idea which came to my mind was using an internet service for MD5 breaking. But... aaarrrggghhh! There's a sault, so the webservice, looking for words over a dictionary fails to find mines...

So the second idea was to take that dictionary from Libre Office and iterate through it. At the end, it worked =) And worked reeeally fast. But that is not an interesting part.

I wandered if I could find those words in my dictionary, generated by my own code.

Artem Shubovych

Whaaaaat?

These days I was given a reeeeally interesting homework at the university. I was given a set of MD5 hashes, calculated from single words (taken from Libre Office' dictionaries) with a given sault. And the task was to find all those words.

So, the first idea which came to my mind was using an internet service for MD5 breaking. But... aaarrrggghhh! There's a sault, so the webservice, looking for words over a dictionary fails to find mines...

So the second idea was to take that dictionary from Libre Office and iterate through it. At the end, it worked =) And worked reeeally fast. But that is not an interesting part.

I wandered if I could find those words in my dictionary, generated by my own code.

Hoooow?

I was thinking of writing it functionally. Really functionally, in Clojure. And, highly motivated by how good Clojure is at parallelism (sarcasm?..) , I started thinking. After many tries and even installing Clojure REPL on my phone and writing code all the way home from university and work, I asked my dear friend to help me with this.

And so we went non-functional way first... We wrote a Java class, having two methods for generating words recursively. The idea was, to make a new word by appending it with each letter, then appending each of the alphabet' letters to this word and so on, until we get all the words of N characters.

When our pretty class was created and working (for some cases) , we decided to do it more Java-correct and created two more classes, implementing a single interface, doing the same thing but differently each. And decided to skip writing context.xml and going deeper with Spring =)

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> java</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">util</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> java</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">util</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stream</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IWordGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">final</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MooWordGenerator</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IWordGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // Best practices in naming convention =)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /** not necessary */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> MooWordGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> completeWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">final</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Character</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> words</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> word </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stream</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Object</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">toString</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">collect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Collectors</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">joining</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // what the fuuck???</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            words</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'a'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'z'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Character</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ncs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ArrayList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ncs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ncs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            completeWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ncs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> words</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    @Override</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">final</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> words </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ArrayList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;>();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Character</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ArrayList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;>();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        completeWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> words</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> words</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> FooWordGenerator</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IWordGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /** */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> StringBuilder</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /** */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> words</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * Creates list of strings containing all possible words with given length.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">@param</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> - the length of words to generate.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">@return</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> List&#x3C;String> words.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     */</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    @Override</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">final</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> allWords </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getAllWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        sb </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        words </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> allWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * Creates list of strings containing all possible words with given length.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * Possible to run this method ONLY ONCE! Next calls will</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * give the wrong result.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">@param</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> - the length of words to generate.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">@return</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> List&#x3C;String> words.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getAllWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">final</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'a'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'c'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> //doesn't work</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            getSB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">append</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                getAllWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">                getWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toString</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            getSB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">deleteCharAt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * Get string builder. create new if null.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">@return</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> sb.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> StringBuilder</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getSB</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">sb </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            sb </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> StringBuilder</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> sb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /**</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * Get words array. create new if null.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     * </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">@return</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> words.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">     */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> List</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getWords</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">words </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            words </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ArrayList</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> words</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Main</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        /** D: go smoke</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">         *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">         *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">         *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">         *</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">         **/</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        IWordGenerator</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gen1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> MooWordGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        IWordGenerator</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gen2 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> FooWordGenerator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Moo:"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gen1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stream</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Foo:"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        gen1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stream</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">forEach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">out</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The solution was made. It worked reaaaally loooooong for words with six letters. I decided to start working on Clojure implementation of this idea. I started writing a function, generating a list of words. Word in this code was represented by a list of numbers from 0 to 25, associated with corresponding letters of latin alphabet. That allowed me not to bore myself with generating a list of chars and use a built-in Clojure' range function.

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gen-words </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        cs</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">gen-words</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dec</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">conj</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cs %</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">range</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 26</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))</span></span></code>

But ended up with the same results as for Java on six letters. Moreover, my implementation gave me strangely-nested list, which caused writing special flattening functions; Clojure's flatten gave me a plain list, where all the words were merged with others.

I needed performance boost!

I tried using pmap instead of map to parallelize the list generation process, but that did not helped. I also tried generating a list of future objects, so each list element will be calculated only when needed:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gen-words </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len cs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        cs</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">future</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">gen-words</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dec</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">conj</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> cs %</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">range</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 26</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))</span></span></code>

But that caused my futures never to be finished. And then my collegue reminded me I can create a function, which will only rely on a previously generated word and will return the next one, not a list of words. "That might save me lot of memory!" , I thought and started coding.

And finished with this pretty implementation:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> next-word </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">prev-word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            l </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop-while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">partial</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = </span><span style="color:#FE640B;--shiki-dark:#EF9F76">25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            l-size </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">-</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">count</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">count</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> l</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            zeroes </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> l-size </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            new-head </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inc</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">first</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> l</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            new-tail </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> l</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">concat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> zeroes </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">new-head</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> new-tail</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span></code>

See, in this implementation no word is being saved nowhere except the return value or an input argument (well, actually the output from a function is then being used as an input for itself) .

I converted all the word representations into words with this over-complicated function:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> word-to-str </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">clojure.string/join</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">+</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> \a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> %</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span></code>

And then I created a function, generating a list of those words.

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> words</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">words</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str-w </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">word-to-str</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">every?</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">partial</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = </span><span style="color:#FE640B;--shiki-dark:#EF9F76">25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">str-w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lazy-seq</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cons</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> str-w </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">words</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">next-word</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))))))</span></span></code>

Yeah, again! But not a plain list or vector, as previously, nooo. I generated a lazy-sequence! This is where Clojure meets ES6 generators =) See, lazy sequence in Clojure is a (possibly) endless collection, each element of which could be evaluated (or assigned a value) when it is needed. Besides that, collection takes almost no memory and its creation costs almost no time. Saying almost I mean the time, needed to construct and store an object in memory. Just a simple, plain class' instance.

But that was not an option - it took nearly 45 minutes to find all the 6-letter words even when using pmap and eaten SO much damn memory!..

However, idle REPL eats much memory too:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> seq-contains? </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">coll target</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">some</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> target %</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> coll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decode-1 </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ws </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">filter</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">seq-contains?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input-hashes </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">encode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> %</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">words</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pmap</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">w </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">encode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> w</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)])</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ws</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span></code>

Then I enhanced this implementation eliminating the lazy-seq completely. So, there was no collection creation at all! All the results were printed onto screen right away when found. This could be replaced with any other storage - file, database, anything! Printing results on the screen is a habit from my student years...

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> decode-2</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">decode-2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">repeat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    ([</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n prev-word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                prev-word-str </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">word-to-str</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">seq-contains?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> input-hashes </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">encode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word-str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">encode</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word-str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word-str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">                nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">if </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">every?</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">partial</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> = </span><span style="color:#FE640B;--shiki-dark:#EF9F76">25</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">                nil</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">recur n </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">next-word</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> prev-word</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))))))</span></span></code>

The memory consumption got minimal:

And the time consumption was not that good, though...

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">task1.core=> </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">time</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">decode-2</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">adbc43d3e1b432aea5e657cd57016de rampa</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bba60169d41b2dce7d0b37b2f9d637e0 kolej</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">7914</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">da949837cbdecf35cbf5951ad518 argon</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">"Elapsed time: 92879.138203 msecs"</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">nil</span></span></code>

Running it from non-REPL environment helped a bit:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">╰─$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> lein</span><span style="color:#40A02B;--shiki-dark:#A6D189"> run</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">4adbc43d3e1b432aea5e657cd57016de</span><span style="color:#40A02B;--shiki-dark:#A6D189"> rampa</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bba60169d41b2dce7d0b37b2f9d637e0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> kolej</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">7914da949837cbdecf35cbf5951ad518</span><span style="color:#40A02B;--shiki-dark:#A6D189"> argon</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">"Elapsed time: 73796.575567 msecs"</span></span></code>

Profit?

But where's the Saint Graal for brute-forcing like that? How to speed that algorithm? I don't know, actually =) Well, I know how to do it with OpenMP , I have a couple of ideas on how this task could be distributed, but those desire a separate article.

Custom logging with timbre urn:uuid:6d2b56df-e8d2-5ac6-a55a-e274202a71cc 2015-10-05T00:00:00Z 2015-10-05T00:00:00Z

Timbre?

At my job we recently started researching logging tools to make our RESTful API, written in Clojure, writing logs in JSON format. We were using Log4j already, but decided to use another tool for this task, making it less painful. So we felt into timbre . Is seemed so easy to use, but it is really undocumented.

According to timbre's API, we needed to define our own appender for writing to a custom JSON file. And we found the output-fn option to configure this behaviour. But it is not documented at all, so we started looking for repositories, using timbre, examples and all the stuff. And finally, we ended up with our own solution.

Underneath you will find description of our way to use timbre from scratch.

Artem Shubovych

Timbre?

At my job we recently started researching logging tools to make our RESTful API, written in Clojure, writing logs in JSON format. We were using Log4j already, but decided to use another tool for this task, making it less painful. So we felt into timbre . Is seemed so easy to use, but it is really undocumented.

According to timbre's API, we needed to define our own appender for writing to a custom JSON file. And we found the output-fn option to configure this behaviour. But it is not documented at all, so we started looking for repositories, using timbre, examples and all the stuff. And finally, we ended up with our own solution.

Underneath you will find description of our way to use timbre from scratch.

Getting started

First of all, you will need a Leiningen project. We already have one, but you may want to create a blank one for the test purpose. But beware, you'd better generate it from an app template, so when you run it with lein run , you face not the problem I faced. The problem was an error I could not get rid of, saying Cannot find anything to run for: my-ns . So I just re-generated project from scratch and the problem gone. I did no research deeper, but if I will, I'll write about it for sure .

Generating project from an app template is done really easily:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lein</span><span style="color:#40A02B;--shiki-dark:#A6D189"> new</span><span style="color:#40A02B;--shiki-dark:#A6D189"> app</span><span style="color:#40A02B;--shiki-dark:#A6D189"> your-app-name</span></span></code>

The process will be finished in seconds. Then you'll need to add a few dependencies in your project.clj :

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defproject</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> your-app-name</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; ...</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    :dependencies </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">org.clojure/clojure </span><span style="color:#40A02B;--shiki-dark:#A6D189">"1.6.0"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                 [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">com.taoensso/timbre </span><span style="color:#40A02B;--shiki-dark:#A6D189">"4.1.4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                 [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">org.clojure/data.json </span><span style="color:#40A02B;--shiki-dark:#A6D189">"0.2.6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]]</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

To install dependencies for your project, simply run lein deps .

Configuring timbre

To use timbre in your project all you need is to require it:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">ns</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timbre-test1.core</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:require </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">taoensso.timbre :as timbre :refer </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info warn debug error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">clojure.data.json :as json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -main </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26; args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">info</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:moo </span><span style="color:#FE640B;--shiki-dark:#EF9F76">-3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:foo :bar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">info</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:some-complicated-hash </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:inner-hash </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:more-inner </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"value1"</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "value2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]}}})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">info</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello, World!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">error</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "SOMETHING WENT WELL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span></code>

This example shows one very important feature of timbre: it can log objects, other than strings and exceptions . This is really handy! Doing so, timbre is able to log a JSON object simply, almost out-of-the-box.

Custom configuration

Now the time has come for something non-trivial. We need to set up our own appender to force timbre log everything in JSON.

There is a set of default appenders in timbre already. For instance, there is a spit appender, writing logs to a file. And the default timbre's appender, writing logs to stdout , is called sample . But there's a trick: each appender in timbre should be configured by its id , not by its type . So you may have two different spit appenders, for example, writing to different files.

Timbre provides two methods of configuration:

  • merging , when you can override only some options of default config
  • setting , when you override all the default options at once

We used the first way, because some of timbre's options were mystical to us - if we do not set them, we will get no output at all. And we have not researched which ones we need to set.

At first, we wrote a simple config, forcing logging to be printed onto a screen with some JSON formatting:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">ns</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timbre-test1.core</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:require </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">taoensso.timbre :as timbre :refer </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info warn debug error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">clojure.data.json :as json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json-output-fn</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  [{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:keys </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vargs_ hostname_ timestamp_ level</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :as args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        messages </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :timestamp @timestamp_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                  :level     level</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                  :hostname  @hostname_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                  :message   msg </span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                   @vargs_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        json-messages </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">json/write-str</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> %</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> messages</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">clojure.string/join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json-messages</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -main </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26; args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">timbre/merge-config!</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:appenders </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 :println </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                    :output-fn json-output-fn</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                 }}})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">info</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:moo </span><span style="color:#FE640B;--shiki-dark:#EF9F76">-3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:foo :bar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Note the appender id: println . This code overrides output-fn for println appender (e. g. the default one) . The parameter for output-fn is a function, receiving a map with different keys. The most important ones are vargs_ , hostname_ , timestamp_ and level . Those are enough to format the correct and full message with any format you might want.

The vargs_ variable contains all the arguments, passed to a logging call ( info , warn , error - any function from timbre namespace, which performs logging) . And the clojure.data.json/write-str function converts its params to JSON and stringifies it, returning valid JSON as a string.

A function should return a string, representing a message, which will be written to a screen or a file, depending on appender.

level argument is set by a macro, you are logging with. For example, timbre/info will set level to "info" , timbre/error - to "error" and so on.

hostname_ and timestamp_ are helper arguments, you might not need them in all the use cases. But the timestamp_ one is really helpful. Always.

Then we overrided the default file appender, extending it with our json-output-fn :

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">ns</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> timbre-test1.core</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:require </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">taoensso.timbre :as timbre :refer </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> info warn debug error</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">taoensso.timbre.appenders.core :as appenders</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">clojure.data.json :as json</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json-output-fn</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  [{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:keys </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vargs_ hostname_ timestamp_ level</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> :as args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">let </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        messages </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fn </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:timestamp @timestamp_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                  :level     level</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                  :hostname  @hostname_</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                                  :message   msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                   @vargs_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        json-messages </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> #</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">json/write-str</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> %</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> messages</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">clojure.string/join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json-messages</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)))</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -main </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26; args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">timbre/merge-config!</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:appenders </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 :spit </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">merge</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">appenders/spit-appender</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:fname </span><span style="color:#40A02B;--shiki-dark:#A6D189">"timbre.log"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:output-fn json-output-fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                 }})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">info</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:moo </span><span style="color:#FE640B;--shiki-dark:#EF9F76">-3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:foo :bar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Nothing new here, except of the appender used - now the application will log to both file and screen. To prevent logging to stdout , we disabled the println appender:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">defn</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> -main </span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26; args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">timbre/merge-config!</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:appenders </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 :println </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:enabled? </span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                 :spit </span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">merge</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">appenders/spit-appender</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:fname </span><span style="color:#40A02B;--shiki-dark:#A6D189">"timbre.log"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:output-fn json-output-fn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                 }})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">info</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:moo </span><span style="color:#FE640B;--shiki-dark:#EF9F76">-3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:foo :bar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">})</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

Here I should mention that we were not made to call our JSON appender spit - it was used for convention reasons only.

And that's basically it - we made our logging to be written to a JSON file only.

Two sides of web application. Part 1: the tools urn:uuid:852610a6-96da-5aef-b3a9-77419787d198 2015-09-20T00:00:00Z 2015-09-20T00:00:00Z

Prologue

How do we usually create a web application? We run a bootstrapping script, which provides us with a skeleton of our application and then we just extend it with the features we need.

That's exactly what we did at the last hackathon we were attending - we started with rails new twf and spent half of the day integrating our blank app with Angular, Paperclip, creating API methods and so on. But the effort we needed to accomplish our goal (quite a simple web app) was really huge.

So I decided to find the best combination of backend and frontend technologies that would cause less pain.

At the project I was recently introduced to, the line between frontend and backend is distinguished very clearly: we have an API, written in Clojure and thin frontend application, made with Angular that works on a generated set of static assets - HTMLs, CSS and JS files (but under the hood we are using HAML and SCSS) .

The application I will be implementing throughout the whole article has the same architecture: it has RESTful API and MVVM on the frontend, made with Angular. I welcome you to the journey of research and new technologies!

Artem Shubovych

Prologue

How do we usually create a web application? We run a bootstrapping script, which provides us with a skeleton of our application and then we just extend it with the features we need.

That's exactly what we did at the last hackathon we were attending - we started with rails new twf and spent half of the day integrating our blank app with Angular, Paperclip, creating API methods and so on. But the effort we needed to accomplish our goal (quite a simple web app) was really huge.

So I decided to find the best combination of backend and frontend technologies that would cause less pain.

At the project I was recently introduced to, the line between frontend and backend is distinguished very clearly: we have an API, written in Clojure and thin frontend application, made with Angular that works on a generated set of static assets - HTMLs, CSS and JS files (but under the hood we are using HAML and SCSS) .

The application I will be implementing throughout the whole article has the same architecture: it has RESTful API and MVVM on the frontend, made with Angular. I welcome you to the journey of research and new technologies!

Why not go with Rails?

Because Rails is often overused. Especially if you install all of frontend libraries (like Angular, Bootstrap, some Angular plugins, etc.) as RubyGems. Frontend should stay on the front end of the application; you should not lock your application at some precise version of the JS script, provided by a gem and rely on author's way to integrate it with Rails.

In our case, Rails is too heavy - when all you need is database + routing + a couple of lightweight controllers, all Rails' features will become a ballast to our app, which must be small, by design.

The goal

Before we start, let's think of what we'll be creating. Will it be a web shop? Or a blog? No, we need something outstanding! Something we've done never before...

After an hour of imaging what it may be, I decided to go with web analytics tool. A prototype, which will be able to tell how many visitors your web application gained recently.

It shouldn't be too complicated, because, you know, it's just a tutorial... So we'll be tracking users' location and browser only. And we'll be displaying those analytics as a chart (values like total visitors, browser usage) and in a table (the same info as the chart) .

Architecture preview

We will be developing our application with two layers (or two sides) - front-end and back-end:

The front-end part is the one the user sees and uses - the web page, mobile or desktop application. The back-end part is the one, which does all the magic - prepares data for the front-end side to display, performs data operations as a reaction on user's actions, etc. Thus we could easily replace either the back-end part or the front-end one or even both and replace them with all brand-new implementation. This architecture allows us to do that really easily.

Build with the right tools!

Now, since we separated our frontend part of application from the backend part, we may use different preprocessing languages to write stylesheets and views. And even controllers! So let's take the most from 2015 and use the newest tool set: Jade , ES6+ and SCSS . And put them all together with Bower and Gulp .

All those Jade, SCSS and ES6 are not supported by a browser out-of-the box. They must be compiled to HTML, CSS and JS in order to be recognized by the browser. But they are here to help you writing code quickly. I listed some of their key features below.

Jade

Jade is a template rendering engine with its own markup language. It is somewhat similar to Haml and Slim - it nests XHTML nodes with indentation, closes tags automatically... But it is especially good at writing complex web pages, consisting of layouts and partials .

Layouts are big templates, containing placeholders, where concrete partials will be placed. So, for example, you may create a separate layout for your webshop' landing page, account page and shopping cart. They will be different. And all of them will use different sets of partials. But, for example, a footer and a quick shopping cart preview or user account widget (the one with a link to user's account page) will be the same. To prevent duplicating those widgets' code on each of the layouts, we extract them to separate files, called partials and then just make a reference (a placeholder) in our layouts, saying "place that partial's content here" .

In case of Jade, we may override or extend existing partials in a layout, without touching partial's file itself. So, for example, if we want to make user's avatar to be shown in a user account widget only on a product page, we just override user widget partial on a product page, removing the part with the avatar.

SCSS

SCSS is a way to simplify writing CSS. It is so simple, yet so powerful, that you will fall in love with it after the first few stylesheets! See, in CSS when you write a long selector, specifying many parents, you may find your stylesheets ugly and huge, when describing different children of one, deeply nested parent.

So, let's say you are having a user widget. And it may be placed both on page's header, footer and sidebar. But the avatar image will look differently on each of those - it must be smaller in header and footer. So you start writing selectors like .sidebar .user-widget .avatar img and .header .user-widget .avatar img . That's painful, but not that much, if you have just a couple of those. However, as your website grows, you start getting really, really upset about that.

And here's where SCSS is just a revelation: its great power is in its selectors , variables and mixins .

Selectors allow you to describe selector' nesting just as you'd be writing C code:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">header</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // header styles</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">user-widget</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // header user-widget styles</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">avatar</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // maybe something differs in avatar itself?</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">            img</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">                // ah! here's it!</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Variables allow you to get rid of all those magic values. So if you use one color many times across your styles, you just extract it into a named constant and use the pretty named value everywhere!

Mixins allow even more: you may extract the parts of the styles into a named and even parametrized function!

Relating on all of those, you may re-write your user widget as follows:

<code><span class="line"><span style="color:#E64553;--shiki-dark:#EA999C">$header-avatar-size</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 50</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#E64553;--shiki-dark:#EA999C">$sidebar-avatar-size</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 150</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">@mixin</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> avatar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$avatar_size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    max-width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#E64553;--shiki-dark:#EA999C"> $avatar_size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    max-height</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#E64553;--shiki-dark:#EA999C"> $avatar_size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">header</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">user-widget</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">avatar</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        @include</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> avatar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">$header-avatar-size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">sidebar</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">user-widget</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">avatar</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        @include</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> avatar</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">$sidebar-avatar-size</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Gulp

I found Gulp to be super-easy for tasks like compiling stylesheets, views and javascripts. But before we continue with Gulp, let's initialize an NPM project with npm init and install the plugins required:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gulp</span></span></code>

And Gulp plugins:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save-dev</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gulp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gulp-babel</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gulp-scss</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gulp-jade</span></span></code>

I will describe how Gulp works and how we can use it in our project in a minute. For now, let's just install the frontend dependencies.

Bower

Let's fix our frontend on specific versions of frontend libraries, so when we update the whole project, nothing gets broken. To make our development quick, we’ll use Twitter Bootstrap . All the frontend dependencies will be managed by a tool called Bower .

Bower is a tool like npm , but used strictly with frontend libraries like jQuery , Angular , Twitter Bootstrap and many others. It's important to keep frontend libraries separate from the backend ones, so we can keep our backend application completely separate from frontend one.

Bower comes with a command-line tool, bower , which we'll use to fill out the bower.json file. It is used by Bower to specify which libraries does our application require:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">npm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> bower</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bower</span><span style="color:#40A02B;--shiki-dark:#A6D189"> init</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bower</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> bootstrap</span><span style="color:#40A02B;--shiki-dark:#A6D189"> angular</span></span></code>

These commands create a directory bower_components , containing all the dependencies installed, each in its own sub-directory. With that in mind, we'll be referencing our frontend dependencies, relatively to their catalogs within the bower_components directory.

Now let's write a build task for Gulp. Gulp is a streamed build tool. That means, that each operation you perform, passes its result to another operation as the input argument. So, for example, if you run gulp.src('src/styles/*.scss') , it'll return you an object with the list of all the SCSS files and the magic pipe() method. And when you call the gulp.src(...).pipe(scss()) , Gulp will pass that list to the SCSS compiler plugin, so you will get a compiled CSS code. That is, not a CSS file itself, but a compressed, merged, CSS file' content.

And that describes the second important feature of Gulp: it does not store the intermediate operation results. It is almost like a functional programming - you just have the input data. Then you call a chain of functions on it, passing the result of one function call to the next function as its input. Same happens here, but in a manner not that strict - since we are using Javascript, we can store the intermediate results in the memory. But to store the results in the files, we should pass them to the gulp.dest(...) function. Depending on the function, looking to store its results, gulp.dest() may point to a directory or a single file, where the results will be stored.

Below is our first Gulp task. Write this code in the gulpfile.js :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gulp </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'gulp'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    sass </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'gulp-scss'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    babel </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'gulp-babel'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    jade </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> require</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'gulp-jade'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'build'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/views/**/*.jade'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">jade</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/javascripts/**/*.js'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">babel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">())</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/javascripts'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/stylesheets/**/*.scss'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sass</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> style</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'expanded'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dest</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/stylesheets'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This tells Gulp to define build task, which compiles all the Jade, SCSS and ES6+ files into HTML, CSS and JS files, correspondingly. Compiled files are placed within the public/ directory, so we may easily render them with almost any web-server. But first things first, we need to prepare directory structure like this for our task:

<code><span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">.</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____bower.json</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____gulpfile.js</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____package.json</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____public</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____src</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____javascripts</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____stylesheets</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">____views</span></span></code>

This may seem odd to the paragraph, dedicated to build tools, but let's check how our tasks work. To do this, we need to write some test files to check our build task. So let's create one of each kind:

src/views/index.jade :

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">lang</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"en"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    meta</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">charset</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"UTF-8"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    title</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> OurStats</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    link</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">rel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"stylesheet"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> href</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/stylesheets/main.css"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    script</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">type</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text/javascript"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"/javascripts/main.js"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    h1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Hello, world!</span></span></code>

src/stylesheets/main.scss :

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">h1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    padding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    border-bottom</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> solid </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dedede</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

src/javascripts/main.js :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> timeout</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">ms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Promise</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> =></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setTimeout</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ms))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">async</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  await</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> timeout</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1000</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  await</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> timeout</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1000</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  console</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">log</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span></code>

Full code of these steps

And to actually check our task, we need to run it with

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">gulp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build</span></span></code>

Now, you may open the HTML generated from Jade in a browser, but it'll look ugly, because your browser will doubtfully find stylesheets and javascripts that easily. To make the magic happen, we will use another Gulp plugin, gulp-server-livereload . Generally, the development process with different build tools looks very similar nowadays: you set up the environment, find the plugins you need, install and configure them - and violà!

I've chosen that server plugin because it comes with one handy feature: it automatically reloads the opened pages in your web-browser if any of the files you are browsing has changed. Here's the code of our serving task:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'serve'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">server</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            livereload</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            directoryListing</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            open</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

But if you remember, we are compiling our sources from SCSS/Jade into the public/ directory. So how the server would know if anything changed in our *.scss or *.jade files? We need to reload the page in web-browser if anything changes in those files. To do that, we'll write one more task, which will re-build our source files if anything changes:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'watch'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">watch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/**/*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'build'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Here we used two new features of Gulp: watching for file changes and running existing tasks from another task . Simple? Yeah, that simple! So we just tell Gulp: keep an eye on those files - if anything happens - run those tasks immediately! - and the magic happens.

But why should we run two tasks? Let's merge them into one so we just run gulp serve and get both live reload and live re-compilation:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">task</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'serve'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">watch</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'src/**/*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [ </span><span style="color:#40A02B;--shiki-dark:#A6D189">'build'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ])</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    gulp</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">src</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'public/'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pipe</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">server</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            port</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3000</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            livereload</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            directoryListing</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            open</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

This task first defines a watcher for our sources and then starts server, which will react to any changes in the public/ directory. To check how this awesomeness works, start gulp serve , open the localhost:3000/test.html page and then change, for example, color for the h1 tag to green. Save the SCSS file and just switch to the browser window, don't reload it manually .

Full code of these steps

Email validation regexp urn:uuid:e61e3808-4cbb-54b5-9514-731f65aeaad7 2015-09-16T00:00:00Z 2015-09-16T00:00:00Z

At my work we've lately been having a discussions on email validation. I recalled a post on habrahabr , showing different options, including effective and psycho solutions.

Artem Shubovych

At my work we've lately been having a discussions on email validation. I recalled a post on habrahabr , showing different options, including effective and psycho solutions.

From CPAN :

Mail::RFC822::Address: regexp-based address validation

This regular expression will only validate addresses that have had any comments stripped and replaced with whitespace (this is done by the module).

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\t]))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*))*@(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*(?:[^()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\] \</span><span style="color:#FE640B;--shiki-dark:#EF9F76">000</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">31</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">r</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">*:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t]))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)*:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*(?:(?:(?:[^()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#FE640B;--shiki-dark:#EF9F76">000</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#FE640B;--shiki-dark:#EF9F76">031</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t]))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\.</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*(?:[^()&#x3C;></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\.</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*(?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span></span>
<span class="line"><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*))*|(?:[^()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\] \</span><span style="color:#FE640B;--shiki-dark:#EF9F76">000</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#FE640B;--shiki-dark:#EF9F76">031</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t]))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*(?:@(?:[^()&#x3C;>@,;</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">.</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*))*(?:,@(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*(?:[^()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\] \</span><span style="color:#FE640B;--shiki-dark:#EF9F76">000</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#FE640B;--shiki-dark:#EF9F76">031</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span></span>
<span class="line"><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \0</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">00-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*))*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\></span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)(?:,</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\s</span><span style="color:#40A02B;--shiki-dark:#A6D189">*(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)(?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">:\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">]]))|"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\.</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*))*(?:,@(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\.</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*))*)*:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*)?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#40A02B;--shiki-dark:#A6D189">"(?:[^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\"\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.|(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))*"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">+|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\Z</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"()&#x3C;>@,;:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]]))</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[([</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\[\]\r\\]</span><span style="color:#179299;--shiki-dark:#81C8BE">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\\</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\](</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[</span><span style="color:#179299;--shiki-dark:#81C8BE">^</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4"> \000</span><span style="color:#40A02B;--shiki-dark:#A6D189">-</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\031</span><span style="color:#40A02B;--shiki-dark:#A6D189">]+(?:(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])+|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\Z</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">|(?=[</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">@</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;:\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">".</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">]))|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[</span><span style="color:#40A02B;--shiki-dark:#A6D189">([^</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\[\]\r\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">]|</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">.)*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\]</span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(?:</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\r\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">)?[ </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\t</span><span style="color:#40A02B;--shiki-dark:#A6D189">])*))*</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\></span><span style="color:#40A02B;--shiki-dark:#A6D189">(?:(</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">?:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">\r\n)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">[ \t])</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">))</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;\s</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span></span></code>

And below is the most effective solution (also matches virtual Gmail addresses with + sign) .

<code><span class="line"><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/.</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189">@</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">.</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\..</span><span style="color:#179299;--shiki-dark:#81C8BE">{2,}</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">i</span></span></code>

To match development addresses, you may want to make it even shorter:

<code><span class="line"><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/.</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189">@</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">.</span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">/</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">i</span></span></code>

You won't believe me, but this is it =)

Irrlicht Newton GD tutorial: prepare to add some Newtonianity urn:uuid:329314ad-1f81-5af6-95f1-374f992b017e 2015-08-29T00:00:00Z 2015-08-29T00:00:00Z

At this point we have an application with

  • 1x Ninja , walking around
  • 1x sphere , hanging in the center of the screen
  • 1x cube , flying around the sphere

That's our "game"? Doubtely... So let's make things move like in real world! Or just like that...

Requirements

First of all, go and get the Newton GD files. And unpack it... right to the source directory of our project! That's right! I'm not insane and I'm aware you are going to put a lot of files in your project. But have no fear - you may always add them to .gitignore and skip them from being tracked in your Git repo:

<code>source/newton-dynamics-master/applications
source/newton-dynamics-master/packages/projects
source/newton-dynamics-master/packages/thirdParty
source/newton-dynamics-master/coreLibrary_300/projects
</code>

You are using Git, right?.. Now, you place the Newton GD sources in your project directory and change your CMakeLists.txt file to look like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.1)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -std=c++11"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"NEWTON_DEMOS_SANDBOX"</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Build demos sandbox"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> OFF</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_PATH source/newton-dynamics-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_INCLUDE_DIRS</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dCustomJoints</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dContainers</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dMath</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTON_LIBRARIES Newton dMath)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${NEWTONGD_PATH})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(X11)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(OpenGL)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(ZLIB)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">NOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> IRRLICHT_LIBRARY_PATH)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    find_library</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_LIBRARY_PATH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            NAMES</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Irrlicht</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            PATHS</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${IRRLICHT_PATH}/lib/</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            PATH_SUFFIXES Linux MacOSX Win32-gcc Win32-visualstudio Win64-visualstudio)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    message</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(STATUS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Found Irrlicht: ${IRRLICHT_LIBRARY_PATH}"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${IRRLICHT_PATH}/include ${NEWTONGD_INCLUDE_DIRS})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCE_FILES source/main.cpp)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCE_FILES})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTON_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${IRRLICHT_LIBRARY_PATH}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${OPENGL_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${ZLIB_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_Xxf86vm_LIB})</span></span></code>

Try to compile your project - it should be just fine. And observe the power of CMake!

Artem Shubovych

At this point we have an application with

  • 1x Ninja , walking around
  • 1x sphere , hanging in the center of the screen
  • 1x cube , flying around the sphere

That's our "game"? Doubtely... So let's make things move like in real world! Or just like that...

Requirements

First of all, go and get the Newton GD files. And unpack it... right to the source directory of our project! That's right! I'm not insane and I'm aware you are going to put a lot of files in your project. But have no fear - you may always add them to .gitignore and skip them from being tracked in your Git repo:

<code>source/newton-dynamics-master/applications
source/newton-dynamics-master/packages/projects
source/newton-dynamics-master/packages/thirdParty
source/newton-dynamics-master/coreLibrary_300/projects
</code>

You are using Git, right?.. Now, you place the Newton GD sources in your project directory and change your CMakeLists.txt file to look like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.1)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -std=c++11"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"NEWTON_DEMOS_SANDBOX"</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Build demos sandbox"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> OFF</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_PATH source/newton-dynamics-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_INCLUDE_DIRS</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dCustomJoints</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dContainers</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dMath</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTON_LIBRARIES Newton dMath)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${NEWTONGD_PATH})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(X11)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(OpenGL)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(ZLIB)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">NOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> IRRLICHT_LIBRARY_PATH)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    find_library</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_LIBRARY_PATH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            NAMES</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Irrlicht</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            PATHS</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${IRRLICHT_PATH}/lib/</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            PATH_SUFFIXES Linux MacOSX Win32-gcc Win32-visualstudio Win64-visualstudio)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    message</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(STATUS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Found Irrlicht: ${IRRLICHT_LIBRARY_PATH}"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${IRRLICHT_PATH}/include ${NEWTONGD_INCLUDE_DIRS})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCE_FILES source/main.cpp)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCE_FILES})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTON_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${IRRLICHT_LIBRARY_PATH}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${OPENGL_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${ZLIB_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_Xxf86vm_LIB})</span></span></code>

Try to compile your project - it should be just fine. And observe the power of CMake!

Gravity

Let's start modifying our Irrlicht sample application. First of all, we will add some Newton headers:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "newton-dynamics-master/coreLibrary_300/source/newton/Newton.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "newton-dynamics-master/packages/dMath/dVector.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "newton-dynamics-master/packages/dMath/dMatrix.h"</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "newton-dynamics-master/packages/dMath/dQuaternion.h"</span></span></code>

The basic thing in the whole Newton GD library is NewtonWorld . That is what it means - the world, where all the physics happen. It is something different from where we place our 3D models. And that should be obvious - graphics are managed by Irrlicht and physics - by Newton. Those are totally different libraries. So we need to tie those two so that graphics correspond to what happens in physical world.

First of all, we need to have a variable for our NewtonWorld . And since physics are handled by scripts too, we need to have that variable close to our other objects - in the ScriptManager class.

There are two functions we need to bind to our NewtonBody :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> transformCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NewtonBody</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> dFloat</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> matrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> threadIndex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // update ISceneNode so that it is in the same position and rotation as the NewtonBody</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> applyForceAndTorqueCallback</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> NewtonBody</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> dFloat</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> timestep</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> threadIndex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // just add gravity to our body</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dFloat Ixx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Iyy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Izz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dFloat mass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodyGetMassMatrix</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Ixx</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Iyy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Izz</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    dVector </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">gravityForce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mass </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">9.8f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    NewtonBodySetForce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gravityForce</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The first one, transformCallback , is called whenever body changes its transform - e. g. either position or rotation. This is a good place to synchronize our Irrlicht meshes' positions with their Newton bodies.

The applyForceAndTorqueCallback function is called on each NewtonUpdate to set the final forces and torques for bodies. We will modify this one later, but for now its implementation is just good.

But what's with that NewtonUpdate ? This is a function, which does as it says: it updates NewtonWorld and all its bodies, taking into account the time since the last update. This function call has one great candidate to be placed into: handleFrame . But we need to modify that method to receive the time since the last frame been rendered and we will use this time to update NewtonWorld too.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> updatePhysics</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">         NewtonUpdate</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> dt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> handleFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> dt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handler </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"handleFrame"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        updatePhysics</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">dt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        setKeyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        handler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Invoke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

Remember about architecture: everything, what needs to be exposed to our scripts should be declared as public in our ScriptManager . Everything else - as protected or private . This is the basic principle of encapsulation , so let's keep it in our application.

And update the main application loop:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // Work out a frame delta time.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u32 now </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTimer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f32 frameDeltaTime </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">now </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> then</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    then </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> now</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    scriptMgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handleFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">frameDeltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Hint: to make simulation slower and so watch ball falling in detail, make the NewtonUpdate argument even smaller. Thousand times, say.

Since we have initialization for our Newton stuff, we need to clean it up at the exit to prevent memory leaks. Let's declare a method for that:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> stopPhysics</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        NewtonDestroyAllBodies</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        NewtonDestroy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">newtonWorld</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

And call it right before the program's end:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scriptMgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">handleExit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">delete</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scriptMgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

And now is the right moment to add key codes' definitions and exit function to our ScriptManager so that we could write more clear code and close our application correctly, using, say, Esc key.

To stop our application, we need to break our while (device->run()) loop. This could be achieved by simply closing the IrrlichtDevice with device->closeDevice() . But we do not have an access to the device from the ScriptManager . So let's add it as a constructor argument:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IrrlichtDevice </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ScriptManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IrrlichtDevice </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneManager </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IVideoDriver </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        driver </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        smgr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        device </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        initPhysics</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

So now we can create a function, exposed to our scripts, which will stop our application:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">closeDevice</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And bind it to the Lua function:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exitFn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CreateFunction</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                [</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> exit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">global</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"exit"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> exitFn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Now we can use our exit function in the Lua scripts. But we will need to use hexadecimal key codes and that's... ugly. So we need to define some symbolic names for those codes:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setGlobalVariables</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setKeyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setKeyCodeConstants</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setKeyCodeConstants</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> keyMapping </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_LBUTTON"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">01</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Left mouse button</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_RBUTTON"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">02</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Right mouse button</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_CANCEL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">03</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Control-break processing</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_MBUTTON"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">04</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Middle mouse button (three-button mouse)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_XBUTTON1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">05</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Windows 2000/XP: X1 mouse button</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_XBUTTON2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">06</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Windows 2000/XP: X2 mouse button</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_BACK"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">08</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // BACKSPACE key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_TAB"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">09</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // TAB key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_CLEAR"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0C</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // CLEAR key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_RETURN"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0D</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ENTER key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SHIFT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // SHIFT key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_CONTROL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">11</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // CTRL key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_MENU"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">12</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ALT key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_PAUSE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">13</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // PAUSE key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_CAPITAL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">14</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // CAPS LOCK key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KANA"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME Kana mode</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_HANGUEL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME Hanguel mode (maintained for compatibility use KEY_HANGUL)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_HANGUL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME Hangul mode</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_JUNJA"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">17</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME Junja mode</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_FINAL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">18</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME final mode</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_HANJA"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">19</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME Hanja mode</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KANJI"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">19</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME Kanji mode</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_ESCAPE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ESC key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_CONVERT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1C</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME convert</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NONCONVERT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1D</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME nonconvert</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_ACCEPT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1E</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME accept</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_MODECHANGE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1F</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // IME mode change request</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SPACE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // SPACEBAR</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_PRIOR"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">21</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // PAGE UP key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NEXT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">22</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // PAGE DOWN key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_END"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">23</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // END key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_HOME"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">24</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // HOME key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_LEFT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">25</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // LEFT ARROW key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_UP"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">26</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // UP ARROW key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_RIGHT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">27</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // RIGHT ARROW key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_DOWN"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">28</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // DOWN ARROW key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SELECT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">29</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // SELECT key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_PRINT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // PRINT key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_EXECUT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // EXECUTE key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SNAPSHOT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2C</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // PRINT SCREEN key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_INSERT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2D</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // INS key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_DELETE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2E</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // DEL key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_HELP"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2F</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // HELP key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_0"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">30</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 0 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">31</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 1 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 2 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">33</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 3 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">34</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 4 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">35</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 5 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">36</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 6 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_7"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">37</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 7 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_8"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">38</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 8 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_9"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">39</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // 9 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_A"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">41</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // A key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_B"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">42</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // B key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_C"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">43</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // C key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_D"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">44</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // D key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_E"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">45</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // E key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_F"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">46</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_G"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">47</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // G key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_H"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">48</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // H key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_I"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">49</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // I key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_J"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // J key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_K"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // K key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_L"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4C</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // L key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_M"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4D</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // M key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_N"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4E</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // N key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_O"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4F</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // O key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_P"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">50</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // P key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_Q"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">51</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Q key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_R"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">52</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // R key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_S"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">53</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // S key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_T"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">54</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // T key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_U"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">55</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // U key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_V"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">56</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // V key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_W"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">57</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // W key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_X"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">58</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // X key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_Y"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">59</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Y key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_KEY_Z"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Z key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_LWIN"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Left Windows key (Microsoft Natural keyboard)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_RWIN"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5C</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Right Windows key (Natural keyboard)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_APPS"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5D</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Applications key (Natural keyboard)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SLEEP"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">5F</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Computer Sleep key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD0"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">60</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 0 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">61</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 1 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">62</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 2 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">63</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 3 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">64</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 4 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">65</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 5 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">66</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 6 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD7"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">67</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 7 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD8"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">68</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 8 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMPAD9"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">69</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Numeric keypad 9 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_MULTIPLY"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Multiply key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_ADD"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Add key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SEPARATOR"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6C</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Separator key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SUBTRACT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6D</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Subtract key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_DECIMAL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6E</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Decimal key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_DIVIDE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">6F</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Divide key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">70</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F1 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">71</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F2 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">72</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F3 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">73</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F4 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">74</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F5 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">75</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F6 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F7"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">76</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F7 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F8"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">77</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F8 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F9"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">78</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F9 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F10"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">79</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F10 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F11"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7A</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F11 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F12"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7B</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F12 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F13"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7C</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F13 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F14"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7D</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F14 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F15"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7E</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F15 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F16"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">7F</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F16 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F17"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">80</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F17 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F18"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">81</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F18 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F19"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">82</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F19 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F20"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">83</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F20 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F21"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">84</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F21 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F22"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">85</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F22 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F23"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">86</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F23 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_F24"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">87</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // F24 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_NUMLOCK"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">90</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // NUM LOCK key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_SCROLL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">91</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // SCROLL LOCK key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_LSHIFT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">A0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Left SHIFT key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_RSHIFT"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">A1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Right SHIFT key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_LCONTROL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">A2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Left CONTROL key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_RCONTROL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">A3</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Right CONTROL key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_LMENU"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">A4</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Left MENU key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_RMENU"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">A5</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Right MENU key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">BA</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for US    ";:"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_PLUS"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">BB</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Plus Key   "+"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_COMMA"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">BC</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Comma Key  ","</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_MINUS"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">BD</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Minus Key  "-"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_PERIOD"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">BE</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Period Key "."</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_2"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">BF</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for US    "/?"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">C0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for US    "`~"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_4"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DB</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for US    "[{"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_5"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DC</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for US    "\|"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_6"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DD</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for US    "]}"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_7"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DE</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for US    "'""</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_8"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">DF</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // None</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_AX"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">E1</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // for Japan "AX"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_102"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">E2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // "&#x3C;>" or "\|"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_ATTN"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">F6</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Attn key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_CRSEL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">F7</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // CrSel key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_EXSEL"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">F8</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // ExSel key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_EREOF"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">F9</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Erase EOF key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_PLAY"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">FA</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Play key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_ZOOM"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">FB</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Zoom key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_PA1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">FD</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // PA1 key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "KEY_OEM_CLEAR"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> 0x</span><span style="color:#FE640B;--shiki-dark:#EF9F76">FE</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Clear key</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> keyMapping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">begin</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> keyMapping</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">it</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">it</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> it</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now we can create a Esc key handler in our script:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> handleFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- Esc</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> KEY_STATE[KEY_ESCAPE] </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        exit</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Now we are ready to create our first Newton bodies. Bodies are some invisible objects, which define how our Irrlicht meshes will behave (e. g. where they will be placed, how they will interact when moving, etc.). Basically, there are two types of bodies:

  1. dynamic , whose movement is determined by the forces, applied to them
  2. kinematic , which are controlled by setting their velocities

Those two kinds of bodies are totally different, so the interactions between them are not pre-defined. So when your dynamic body will fall onto a kinematic one, it will fall through.

And each body has its shape, which determines behaviour of the body, when it collides others and the collision detection itself, of course. Shapes could be convex or concave . Convex shapes are easier to work with (on the level of physics simulation) , but not all the bodies in practice are convex. For example, levels are oftenly concave. So they need their special shapes, which are called Triangle Mesh .

Note: to keep the performance of your application high, try to minimalize the use of triangle meshes and use as simple shapes, as possible. Sometimes it is more effective to combine a set of primitive shapes, like spheres, cylinders and boxes into one compound shape, then to use a trimesh.

Let's create our first simple scene, empowered with physics! We will need only two things:

  1. a sphere
  2. the floor

Since we do not have the good mesh in standard Irrlicht distribution for the floor (there is a Quake-like level, but that is too much for our case) , we will learn how to make that simple thing in Blender. The next part is a short break between coding sessions.

Next chapter

Irrlicht Newton GD tutorial: first script urn:uuid:98c43e81-068d-58cc-ad83-4e3f6e933560 2015-08-28T00:00:00Z 2015-08-28T00:00:00Z

As we discussed, we will describe the whole game in scripts, and the core functionality we will define in the core. In this chapter we will be adding Lua to our application. You do not need to download Lua itself - you'd better install it with your system's package manager ( yum or apt or whatever your Linux uses, brew for OSX...) .

Dependencies

The only thing you need to download from Internet this time is Lua wrapper called luacppinterface . So go and get it from Github.

And unpack it... right to the source directory of our project! That's right! That's really small library so it will not pollute your project with tons of files.

Now, I mentioned dependency managers earlier. This is how we will handle them in our C++ application - we will simply put the sources of all the libraries we depend on, with the versions we depend on, right in our project. Given that, you may put Irrlicht there as well - you are free to do anything with our project!

Artem Shubovych

As we discussed, we will describe the whole game in scripts, and the core functionality we will define in the core. In this chapter we will be adding Lua to our application. You do not need to download Lua itself - you'd better install it with your system's package manager ( yum or apt or whatever your Linux uses, brew for OSX...) .

Dependencies

The only thing you need to download from Internet this time is Lua wrapper called luacppinterface . So go and get it from Github.

And unpack it... right to the source directory of our project! That's right! That's really small library so it will not pollute your project with tons of files.

Now, I mentioned dependency managers earlier. This is how we will handle them in our C++ application - we will simply put the sources of all the libraries we depend on, with the versions we depend on, right in our project. Given that, you may put Irrlicht there as well - you are free to do anything with our project!

Build instructions

To build our project we will need to change our CMakeLists.txt file to fetch our new dependency:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.1)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -std=c++11"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCE_FILES source/main.cpp)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(LUACPPINTERFACE_PATH source/luacppinterface-master)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${LUACPPINTERFACE_PATH})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(X11)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(OpenGL)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(ZLIB)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Lua)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">NOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> IRRLICHT_LIBRARY_PATH)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    find_library</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_LIBRARY_PATH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            NAMES</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Irrlicht</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            PATHS</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${IRRLICHT_PATH}/lib/</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            PATH_SUFFIXES Linux MacOSX Win32-gcc Win32-visualstudio Win64-visualstudio)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    message</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(STATUS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Found Irrlicht: ${IRRLICHT_LIBRARY_PATH}"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${IRRLICHT_PATH}/include ${LUA_INCLUDE_DIR} ${LUACPPINTERFACE_PATH}/include)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCE_FILES})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        luacppinterface</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${IRRLICHT_LIBRARY_PATH}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${OPENGL_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${ZLIB_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_Xxf86vm_LIB}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LUA_LIBRARIES})</span></span></code>

And here's the thing: if you try to compile our project on another machine, you will not need to install any other libraries than Lua on that machine! That supposed to sound like "sweet, huh?" , except that one little "but..." ... Bittersweet...

Back to our busines... luacppinterface needs to be tweaked a bit to fit our project - we will hack its CMakeLists.txt file to make it depend on system Lua libraries. Just make it look like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (VERSION 2.6)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(luacppinterface)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"lua/src"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Lua)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${LUA_INCLUDE_DIR})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_library</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(luacppinterface STATIC</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    include</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">/luacoroutine.cpp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    include</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">/luareference.cpp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    include</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">/luacppinterface.cpp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    include</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">/luatable.cpp</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    include</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">/luafunction.cpp</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(luacppinterface ${LUA_LIBRARIES})</span></span></code>

It barely differs from the original file, but it makes a compilation pleasant - you do not need to specify paths to Lua libs anymore!

Injecting some Lua

Our application now uses C++ code to place some 3D objects in a scene. Let's move, say, sphere creation, to the script.

First of all, add luacppinterface headers to our main.cpp file:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "luacppinterface-master/include/luacppinterface.h"</span></span></code>

Now let's look at some of Irrlicht' conventions:

  • it uses irr::video::IVideoDriver for rendering operations
  • it uses irr::scene::ISceneManager for scene management

So why not to define a ScriptManager to handle scripts? Our requirements for this class (for now) are:

  • it should load and evaluate scripts
  • it should provide simple API to our scripts

Let's get coding!

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ScriptManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    Lua luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IVideoDriver </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneManager </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> bindFunctions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ScriptManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ISceneManager</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">IVideoDriver</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        driver </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        smgr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createSphereNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> textureFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setNodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> LuaTable</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    LuaTable</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getNodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loadScript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> filename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ifstream </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">filename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">istreambuf_iterator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">inf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">istreambuf_iterator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        bindFunctions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">RunScript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

This is just a skeleton - we will fill it out in a minute. Just catching up:

  1. this class depends on IVideoDriver and ISceneManager to handle 3D objects and the scene
  2. it contains Lua luaState field to store the current state of our script running
  3. it stores all the nodes as a &#x3C;string, ISceneNode*> map to allow access to our nodes from scripts
  4. it exposes three methods as an API to Lua scripts: createSphereNode , setNodePosition and getNodePosition so we will be able to make some manipulations in our scripts
  5. it provides really short and simple interface to our C++ core: ScriptManager(...) and loadScript

The main principle, each and every programmer breaks every day is KISS (Keep It Stupidly Simple) . And that principle should guide us through this whole tutorial to not overthink and override ourselves as well as the project we are making. That is why our APIs are that simple.

But let's get back to our ScriptManager . It shows how things will look like, but never defines how they will actually work . So here are the key points to Lua API:

  1. LuaTable is an array-like structure in Lua, representing both indexed as well as key-value arrays in Lua. This type is a way to pass variables between Lua script and C++ program. You may use both table.Get&#x3C;value_type>(index) and table.Get&#x3C;value_type>("key") methods to access its values.

  2. To bind our ScriptManager methods to Lua functions, we need to use pointers to those functions. And as it is not that simple in usual C++, we will use C++11x lambdas:

    <code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createSphere </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">CreateFunction</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#7C7F93;--shiki-dark:#949CBB">](</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createSphereNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> });</span></span></code>
  3. All the functions and variables you want to pass to Lua scripts should be global. And since we have our pretty luaState member, we may set global members through its methods:

    <code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaTable global </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">global</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"createSphere"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> createSphere</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>
  4. We will be using just a map of a Irrlicht' nodes and its name to bypass those nodes between scripts and core:

    <code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createSphereNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> textureFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
    <span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">  scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addSphereSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">textureFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()));</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialFlag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMF_LIGHTING</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
    <span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setNodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> LuaTable</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
    <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"x"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"y"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"z"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
    <span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">  LuaTable</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getNodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      LuaTable pos </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">CreateTable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">      core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df v </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> nodes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"x"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"y"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"z"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
    <span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span></code>

Given those, we have our API and are able to create and run our first Lua script. Add one in the media/scripts/ directory:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createSphere</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sphere1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/textures/wall.webp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Note: paths in the script will be used by C++ core, relatively to the binary file, which is... generated by our C++ code! So all the paths in the scripts are just the same as they are in C++ core.

And add the ScriptManager initialization code:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ScriptManager </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scriptMgr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;font-weight:bold;--shiki-dark:#CA9EE6;--shiki-dark-font-weight:bold"> new</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ScriptManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scriptMgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">loadScript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/scripts/test1.lua"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Now you may remove the code, creating sphere in the main() function. And run the code. You should see exactly the same picture as before:

Homework

Your task is: try to move all the other "factory" functions (creating cube, ninja, circle animator for cube and fly animator for Ninja) to Lua script, adding API for them to ScriptManager .

More separation

We will now advance our script and add some convention to it. These will be our tasks for the rest of this chapter:

  1. move keyboard events handling to script
  2. create two function in script so we may call them by convention, not by configuration

The last phrase I took from Ember.js introduction . It says "prefer convention over configuration" , meaning we'd better call the functions of same name on different scripts, instead of setting somehow which function to call.

That is, we will define handleFrame() function in our script, which will be called on each onFrame event in our C++ core and the main() function, which will be called right after script has been loaded.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handler </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"handleFrame"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Invoke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Moreover, we will define a global keyboard state table for each of scripts we load and will be updating it as user presses keys on his keyboard. And this variable will be shared with script, but as read-only one. So changes in that table will have no effect on the application itself.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ScriptManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">map</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> keyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setGlobalVariables</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        setKeyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setKeyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        LuaTable keysTable </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">CreateTable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">kv </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> keyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            keysTable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">kv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> kv</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">second</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"KEY_STATE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> keysTable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> setKeyState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        keyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> state</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> handleFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handler </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"handleFrame"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        setKeyStates</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        handler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Invoke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> loadScript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> filename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ifstream </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">inf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">filename</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">string </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">istreambuf_iterator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">inf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)),</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">istreambuf_iterator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        bindFunctions</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        setGlobalVariables</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">RunScript</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">code</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scriptMainFn </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"main"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        scriptMainFn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Invoke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    MyEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">ScriptManager</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">scriptManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        scriptMgr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> scriptManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u32 i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> KEY_KEY_CODES_COUNT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            scriptMgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setKeyState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // This is the one method that we have to implement</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> SEvent</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // Remember whether each key is down or up</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_KEY_INPUT_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            scriptMgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setKeyState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KeyInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KeyInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PressedDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ScriptManager </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">scriptMgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Variables are added to a GlobalEnvironment just as function do:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"KEY_STATE"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> keysTable</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Lua-defined functions are found by their names and called with Invoke(args) method:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">auto</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> handler </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> luaState</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">GetGlobalEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Get</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">LuaFunction</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">>></span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"handleFrame"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handler</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Invoke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Let's add some simple interaction to our script now. I'll help you a bit:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moveNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> std</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">string</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> LuaTable</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> findNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df vec </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> tableToVector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pos</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">matrix4 m</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df rot </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    m</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setRotationDegrees</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">rot</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    m</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">transformVect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">updateAbsolutePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This is how nodes could be moved relatively to their current position in Irrlicht.

And here's how our Lua script may look like now:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> handleFrame</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- w</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> KEY_STATE[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x57</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        move</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sphere1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> })</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    -- s</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> KEY_STATE[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0x53</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#D20F39;--shiki-dark:#E78284"> true</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        move</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sphere1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> })</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    createSphere</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sphere1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/textures/wall.webp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setPosition</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sphere1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> })</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    createCube</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"cube1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/textures/t351sml.webp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    addCircleAnimator</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"cube1"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">20.0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    createAnimatedMesh</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ninja"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/models/ninja.b3d"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">"media/textures/nskinbl.webp"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">13</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setRotation</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ninja"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">90</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> })</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    setScale</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ninja"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> })</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    addForwardAnimator</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"ninja"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 60</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }, { x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, y </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, z </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 60</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">3500</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">true</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

If you run our application now , you should be able to control sphere with w and s keys:

Next chapter

Irrlicht Newton GD tutorial: first application urn:uuid:c54a7ea0-5bcd-5b7d-9c9d-97ba0b5319c7 2015-08-27T00:00:00Z 2015-08-27T00:00:00Z

Install Irrlicht

First of all, you will definetely need the Irrlicht engine, so go get it .

Then you will need to compile it. Compilation process depends on the operating system you use, but it's really similar on every one.

Linux

Install these dependencies with your system' package manager: libenet-dev libxxf86vm-dev zlib-dev cmake .

Unzip Irrlicht, go to the directory you unpacked with the terminal and run the following:

<code><span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">cd</span><span style="color:#40A02B;--shiki-dark:#A6D189"> source/Irrlicht</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make</span></span></code>

Belive it or not, but that's all!

Windows

Unzip Irrlicht, go to the directory you unpacked and open the VisualStudio project (depending on VisualStudio version, you might want to open a bit different file) in source/Irrlicht :

<code>Irrlicht10.0.sln
Irrlicht11.0.sln
Irrlicht8.0.sln
Irrlicht9.0.sln
</code>

Build it with VisualStudio - and you are done!

MacOS X

The steps are a bit complicated. And they require you to install XCode and Command-Line Tools - those could be found either in AppStore or on the Apple website.

  • First of all, you need to install a bunch of dependencies (I use brew for this purpose) :

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">brew</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> tinyxml</span><span style="color:#40A02B;--shiki-dark:#A6D189"> enet</span><span style="color:#40A02B;--shiki-dark:#A6D189"> lua</span><span style="color:#40A02B;--shiki-dark:#A6D189"> cmake</span></span></code>
  • Get a list of all compilers available for your OSX version:

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">xcodebuild</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -showBuildSettings</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> grep</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DEFAULT_COMPILER</span></span></code>

    I got something like this:

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> xcodebuild</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -showBuildSettings</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> grep</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DEFAULT_COMPILER</span></span>
    <span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  DEFAULT_COMPILER</span><span style="color:#40A02B;--shiki-dark:#A6D189"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> com.apple.compilers.llvm.clang.1_0</span></span></code>
  • Now the build process:

    <code><span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">cd</span><span style="color:#40A02B;--shiki-dark:#A6D189"> source/Irrlicht/MacOSX</span></span>
    <span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">xcodebuild</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -project</span><span style="color:#40A02B;--shiki-dark:#A6D189"> MacOSX.xcodeproj</span><span style="color:#40A02B;--shiki-dark:#A6D189"> GCC_VERSION=com.apple.compilers.llvm.clang.1_0</span></span></code>
  • And the final step - copy the library to the lib/MacOSX directory:

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build/Release/libIrrlicht.a</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ../../../lib/MacOSX</span></span></code>

Phew! That's a damn bunch of commands, don't you think?

Artem Shubovych

Install Irrlicht

First of all, you will definetely need the Irrlicht engine, so go get it .

Then you will need to compile it. Compilation process depends on the operating system you use, but it's really similar on every one.

Linux

Install these dependencies with your system' package manager: libenet-dev libxxf86vm-dev zlib-dev cmake .

Unzip Irrlicht, go to the directory you unpacked with the terminal and run the following:

<code><span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">cd</span><span style="color:#40A02B;--shiki-dark:#A6D189"> source/Irrlicht</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make</span></span></code>

Belive it or not, but that's all!

Windows

Unzip Irrlicht, go to the directory you unpacked and open the VisualStudio project (depending on VisualStudio version, you might want to open a bit different file) in source/Irrlicht :

<code>Irrlicht10.0.sln
Irrlicht11.0.sln
Irrlicht8.0.sln
Irrlicht9.0.sln
</code>

Build it with VisualStudio - and you are done!

MacOS X

The steps are a bit complicated. And they require you to install XCode and Command-Line Tools - those could be found either in AppStore or on the Apple website.

  • First of all, you need to install a bunch of dependencies (I use brew for this purpose) :

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">brew</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> tinyxml</span><span style="color:#40A02B;--shiki-dark:#A6D189"> enet</span><span style="color:#40A02B;--shiki-dark:#A6D189"> lua</span><span style="color:#40A02B;--shiki-dark:#A6D189"> cmake</span></span></code>
  • Get a list of all compilers available for your OSX version:

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">xcodebuild</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -showBuildSettings</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> grep</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DEFAULT_COMPILER</span></span></code>

    I got something like this:

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> xcodebuild</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -showBuildSettings</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> grep</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DEFAULT_COMPILER</span></span>
    <span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  DEFAULT_COMPILER</span><span style="color:#40A02B;--shiki-dark:#A6D189"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> com.apple.compilers.llvm.clang.1_0</span></span></code>
  • Now the build process:

    <code><span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">cd</span><span style="color:#40A02B;--shiki-dark:#A6D189"> source/Irrlicht/MacOSX</span></span>
    <span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">xcodebuild</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -project</span><span style="color:#40A02B;--shiki-dark:#A6D189"> MacOSX.xcodeproj</span><span style="color:#40A02B;--shiki-dark:#A6D189"> GCC_VERSION=com.apple.compilers.llvm.clang.1_0</span></span></code>
  • And the final step - copy the library to the lib/MacOSX directory:

    <code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build/Release/libIrrlicht.a</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ../../../lib/MacOSX</span></span></code>

Phew! That's a damn bunch of commands, don't you think?

Common

By performing those steps, described above, you will end up with the compiled Irrlicht library file within the lib/ directory, depending on your platform:

<code>Linux/libIrrlicht.a
MacOSX/libIrrlicht.a
Win32-visualstudio/Irrlicht.lib
Win64-visualStudio/Irrlicht.lib
</code>

Now, create a blank project in your favorite IDE and proceed...

Application itself

Our first application will show you Irrlicht basic features we will use later. They are:

  • mesh handling - loading, rendering, animating, etc.
  • user input handling - reacting to keyboard and mouse events
  • user interface (UI) - displaying some information within the application window

The good start for that is standard example from Irrlicht pack, the 04 - Movement one. Let's take a look over its code:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/** Example 004 Movement</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">This Tutorial shows how to move and animate SceneNodes. The</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">basic concept of SceneNodeAnimators is shown as well as manual</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">movement of nodes using the keyboard.  We'll demonstrate framerate</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">independent movement, which means moving by an amount dependent</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">on the duration of the last run of the Irrlicht loop.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">Example 19.MouseAndJoystick shows how to handle those kinds of input.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">As always, I include the header files, use the irr namespace,</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">and tell the linker to link with the .lib file.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">*/</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#ifdef</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> _MSC_VER</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// We'll also define this to stop MSVC complaining about sprintf().</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#define</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> _CRT_SECURE_NO_WARNINGS</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#pragma</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> comment</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">lib</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Irrlicht.lib"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#endif</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;irrlicht.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">using</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> namespace</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">To receive events like mouse and keyboard input, or GUI events like "the OK</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">button has been clicked", we need an object which is derived from the</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">irr::IEventReceiver object. There is only one method to override:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">irr::IEventReceiver::OnEvent(). This method will be called by the engine once</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">when an event happens. What we really want to know is whether a key is being</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">held down, and so we will remember the current state of each key.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">*/</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> MyEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IEventReceiver</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // This is the one method that we have to implement</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> SEvent</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // Remember whether each key is down or up</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EventType </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EET_KEY_INPUT_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            KeyIsDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KeyInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KeyInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">PressedDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // This is used to check whether a key is being held down</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> IsKeyDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">EKEY_CODE</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> keyCode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> const</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> KeyIsDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">keyCode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    MyEventReceiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u32 i</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KEY_KEY_CODES_COUNT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ++</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            KeyIsDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">private</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // We use this array to store the current state of each key</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    bool</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> KeyIsDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KEY_KEY_CODES_COUNT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">The event receiver for keeping the pressed keys is ready, the actual responses</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">will be made inside the render loop, right before drawing the scene. So lets</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">just create an irr::IrrlichtDevice and the scene node we want to move. We also</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">create some other additional scene nodes, to show that there are also some</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">different possibilities to move and animate scene nodes.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">*/</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // create device</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    MyEventReceiver receiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    IrrlichtDevice</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> createDevice</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EDT_OPENGL</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dimension2d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">u32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">640</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 480</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">receiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // could not create selected driver.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IVideoDriver</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getVideoDriver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneManager</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getSceneManager</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    Create the node which will be moved with the WSAD keys. We create a</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    sphere node, which is a built-in geometry primitive. We place the node</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    at (0,0,30) and assign a texture to it to let it look a little bit more</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    interesting. Because we have no dynamic lights in this scene we disable</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    lighting for each model (otherwise the models would be black).</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    */</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addSphereSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"../../media/wall.webp"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialFlag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMF_LIGHTING</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    Now we create another node, movable using a scene node animator. Scene</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    node animators modify scene nodes and can be attached to any scene node</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    like mesh scene nodes, billboards, lights and even camera scene nodes.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    Scene node animators are not only able to modify the position of a</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    scene node, they can also animate the textures of an object for</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    example. We create a cube scene node and attach a 'fly circle' scene</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    node animator to it, letting this node fly around our sphere scene node.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    */</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addCubeSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"../../media/t351sml.webp"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialFlag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMF_LIGHTING</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNodeAnimator</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> anim </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createFlyCircleAnimator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">30</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20.0f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">anim</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addAnimator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">anim</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            anim</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    The last scene node we add to show possibilities of scene node animators is</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    a b3d model, which uses a 'fly straight' animator to run between to points.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    */</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IAnimatedMeshSceneNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> anms </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addAnimatedMeshSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getMesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"../../media/ninja.b3d"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">anms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNodeAnimator</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> anim </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createFlyStraightAnimator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">60</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">100</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">60</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3500</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">anim</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            anms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addAnimator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">anim</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            anim</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        To make the model look right we disable lighting, set the</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        frames between which the animation should loop, rotate the</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        model around 180 degrees, and adjust the animation speed and</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        the texture. To set the right animation (frames and speed), we</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        would also be able to just call</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        "anms->setMD2Animation(scene::EMAT_RUN)" for the 'run'</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        animation instead of "setFrameLoop" and "setAnimationSpeed",</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        but this only works with MD2 animations, and so you know how to</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        start other animations. But a good advice is to not use</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        hardcoded frame-numbers...</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        */</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        anms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setMaterialFlag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">EMF_LIGHTING</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        anms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFrameLoop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 13</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        anms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAnimationSpeed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//      anms->setMD2Animation(scene::EMAT_RUN);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        anms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setScale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        anms</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">90</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//      anms->setMaterialTexture(0, driver->getTexture("../../media/sydney.webp"));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    To be able to look at and move around in this scene, we create a first</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    person shooter style camera and make the mouse cursor invisible.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    */</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addCameraSceneNodeFPS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getCursorControl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setVisible</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">false</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    Add a colorful irrlicht logo</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    */</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getGUIEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addImage</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTexture</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"../../media/irrlichtlogoalpha2.tga"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">position2d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">    gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIStaticText</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> diagnostics </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getGUIEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addStaticText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        L""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 400</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    diagnostics</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setOverrideColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    We have done everything, so lets draw it. We also write the current</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    frames per second and the name of the driver to the caption of the</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    window.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    */</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> lastFPS </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // In order to do framerate independent movement, we have to know</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // how long it was since the last frame</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    u32 then </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTimer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // This is the movemen speed in units per second.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f32 MOVEMENT_SPEED </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    while</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // Work out a frame delta time.</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u32 now </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTimer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f32 frameDeltaTime </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">now </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> then</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1000.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // Time in seconds</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        then </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> now</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        /* Check if keys W, S, A or D are being held down, and move the</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        sphere node around respectively. */</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">        core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">vector3df nodePosition </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">receiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">IsKeyDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KEY_KEY_W</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            nodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MOVEMENT_SPEED </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> frameDeltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">receiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">IsKeyDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KEY_KEY_S</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            nodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MOVEMENT_SPEED </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> frameDeltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">receiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">IsKeyDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KEY_KEY_A</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            nodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">-=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MOVEMENT_SPEED </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> frameDeltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">receiver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">IsKeyDown</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">irr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">KEY_KEY_D</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            nodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> MOVEMENT_SPEED </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> frameDeltaTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">nodePosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">beginScene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">113</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">113</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76">133</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // draw the 3d scene</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getGUIEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // draw the gui environment (the logo)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endScene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fps </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getFPS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lastFPS </span><span style="color:#179299;--shiki-dark:#81C8BE">!=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">            core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stringw </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">tmp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">L"Movement Example - Irrlicht Engine ["</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            tmp </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            tmp </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> L"] fps: "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            tmp </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setWindowCaption</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tmp</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c_str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            lastFPS </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> fps</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    /*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    In the end, delete the Irrlicht device.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    */</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/*</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">That's it. Compile and play around with the program.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">**/</span></span></code>

Building the project

Paste the code from above to your blank project in your IDE, in the source/main.cpp file. This may differ, but is not critical. Now, add the CMakeLists.txt file to your project and fill it with these commands:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.1)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -std=c++11"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(X11)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(OpenGL)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(ZLIB)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">NOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> IRRLICHT_LIBRARY_PATH)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    find_library</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_LIBRARY_PATH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            NAMES</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Irrlicht</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            PATHS</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${IRRLICHT_PATH}/lib/</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            PATH_SUFFIXES Linux MacOSX Win32-gcc Win32-visualstudio Win64-visualstudio)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    message</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(STATUS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Found Irrlicht: ${IRRLICHT_LIBRARY_PATH}"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${IRRLICHT_PATH}/include)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCE_FILES source/main.cpp)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCE_FILES})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${IRRLICHT_LIBRARY_PATH}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${OPENGL_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${ZLIB_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_Xxf86vm_LIB})</span></span></code>

Note: for those of you, guys, running MacOS X I prepared a bit more complicated CMakeLists.txt file - just to make our application run everywhere:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.1)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -std=c++11"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">option</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"NEWTON_DEMOS_SANDBOX"</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Build demos sandbox"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> OFF</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(LUACPPINTERFACE_PATH source/luacppinterface-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CPPFORMAT_PATH source/cppformat-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_PATH source/newton-dynamics-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_INCLUDE_DIRS</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dCustomJoints</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dContainers</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dMath)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTON_LIBRARIES Newton dMath)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${LUACPPINTERFACE_PATH})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${CPPFORMAT_PATH})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${NEWTONGD_PATH})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(X11)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(OpenGL)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(ZLIB)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Lua)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">NOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> IRRLICHT_LIBRARY_PATH)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (UNIX)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX Linux)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (APPLE)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX MacOSX)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (WIN32)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (MSVC)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX Win32-visualstudio Win64-visualstudio)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (MINGW)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX Win32-gcc)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    find_library</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_LIBRARY_PATH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            NAMES</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Irrlicht</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            PATHS</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${IRRLICHT_PATH}/lib/</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            PATH_SUFFIXES ${IRRLICHT_PATH_SUFFIX})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    message</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(STATUS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Found Irrlicht: ${IRRLICHT_LIBRARY_PATH}"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(LIBRARIES luacppinterface</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        cppformat</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTON_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${IRRLICHT_LIBRARY_PATH}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${X11_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${OPENGL_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${ZLIB_LIBRARIES}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LUA_LIBRARIES})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">NOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> APPLE)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(LIBRARIES ${LIBRARIES} ${X11_Xxf86vm_LIB})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${IRRLICHT_PATH}/include</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LUA_INCLUDE_DIR}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LUACPPINTERFACE_PATH}/include</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${CPPFORMAT_PATH}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_INCLUDE_DIRS})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCE_FILES source/main.cpp)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCE_FILES})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (APPLE)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -framework Foundation -framework OpenGL -framework Cocoa -framework Carbon -framework AppKit -framework IOKit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LIBRARIES})</span></span></code>

CMake file

But what happens in all that code? First two lines of our CMakeLists.txt file define the project:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">cmake_minimum_required</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(VERSION 3.1)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">project</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(irrlicht_newton_game1)</span></span></code>

Then we modify the variable CMAKE_CXX_FLAGS , which will be used to set compiler flags. This is how we add items to lists or modify string variables with CMake: we set it the new value, consisting of the old one and the new elements / parts:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -std=c++11"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

Then we tell CMake not to build Newton demo sandbox subproject and set a few path variables - we will use them to point compiler to the header and library files of our third-party libraries (like Newton itself, Irrlicht and others).

Remember: these are only plain variables, they have no effect on compiler themselves.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(LUACPPINTERFACE_PATH source/luacppinterface-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CPPFORMAT_PATH source/cppformat-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_PATH source/newton-dynamics-master)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTONGD_INCLUDE_DIRS</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dCustomJoints</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dContainers</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_PATH}/packages/dMath)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(NEWTON_LIBRARIES Newton dMath)</span></span></code>

Next, we point CMake to our sub-projects, which are by the fact our third-party libraries:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${LUACPPINTERFACE_PATH})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${CPPFORMAT_PATH})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_subdirectory</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${NEWTONGD_PATH})</span></span></code>

These tell CMake to build sub-projects before building our application. Because our sub-projects are nothing but libraries, we can then look for the built libraries, required by our project in the sub-projects' output directories like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(Lua)</span></span></code>

Same way we look for system libraries:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(X11)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(OpenGL)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">find_package</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(ZLIB)</span></span></code>

These commands set compile-ready variables like X11_LIBRARIES .

Some sub-projects may set CMake variables too, providing us with paths to include files or library files. If Irrlicht did not do this, we try to find its paths with CMake:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">NOT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> IRRLICHT_LIBRARY_PATH)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (UNIX)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX Linux)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (APPLE)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX MacOSX)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (WIN32)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (MSVC)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX Win32-visualstudio Win64-visualstudio)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (MINGW)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_PATH_SUFFIX Win32-gcc)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    find_library</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(IRRLICHT_LIBRARY_PATH</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            NAMES</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Irrlicht</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            PATHS</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${IRRLICHT_PATH}/lib/</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            PATH_SUFFIXES ${IRRLICHT_PATH_SUFFIX})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    message</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(STATUS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"Found Irrlicht: ${IRRLICHT_LIBRARY_PATH}"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span></code>

Note the environment variables CMake provides us with: UNIX , APPLE , WIN32 , MSVC and many others. They describe which operating system CMake was ran under and which compiler it was told to use.

And the most important part of our CMakeLists.txt file:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">include_directories</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${IRRLICHT_PATH}/include</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LUA_INCLUDE_DIR}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LUACPPINTERFACE_PATH}/include</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${CPPFORMAT_PATH}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${NEWTONGD_INCLUDE_DIRS})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(SOURCE_FILES source/main.cpp)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(EXECUTABLE_NAME irrlicht_newton_game1)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCE_FILES})</span></span></code>

This actually runs the compiler with the include directories, source files and output file specified.

After that, we may run linker to link the intermediate object files, provided by compiler, and end up with the application executable:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">target_link_libraries</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME}</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        ${LIBRARIES})</span></span></code>

For OSX users there is a small hack, needed to build the application:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (APPLE)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(CMAKE_CXX_FLAGS </span><span style="color:#40A02B;--shiki-dark:#A6D189">"${CMAKE_CXX_FLAGS} -framework Foundation -framework OpenGL -framework Cocoa -framework Carbon -framework AppKit -framework IOKit"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span></code>

Note the order the commands are specified in: having include path variables definitions placed before sub-projects commands may be no harmful, but more "effective" commands, like compiling sub-projects ( add_subdirectory ) depend on other CMake commands, so be sure to keep the order sane and clean.

Running the build

Now that you are ready, run the following commands from your project directory (you will need cmake to be installed in your system) :

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mkdir</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">cd</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cmake</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -DIRRLICHT_PATH=path_to_directory_where_you_unpacked_irrlicht</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ..</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">make</span></span></code>

Warning: do not forget to replace path_to_directory_where_you_unpacked_irrlicht with the actual path to the directory, where your Irrlicht files lay!

This will build our first Irrlicht application. Not obvious how handy it is right now, but you will see the power of CMake in our later sessions.

Before you run the application, copy the whole media directory from the Irrlicht dir to the parent dir of your project. You should end up with directory structure like this:

<code>.
└── irrlicht_newton_tutorials
    ├── irrlicht_newton_game1
    │   ├── build
    │   ├── CMakeLists.txt
    │   └── source
    │       └── main.cpp
    └── media
</code>

Note: If you now just run the irrlicht_newton_game1 binary on OSX, you will see your application does not react to keyboard events. This is tricky, but you need to pack your application as OSX application. This is easy, though: just create a directory tree mkdir -p irrlicht_newton_game1.app/Contents/MacOS/ and move your binary file there:

<code>├── irrlicht_newton_game1.app
│   └── Contents
│       └── MacOS
│           └── irrlicht_newton_game1
</code>

Open Finder and run the application from there. On other operating systems run the executable file in your build directory.

Buuuuut, since we have CMake, we may simplify this task because this is a part of application build process. So we need to create a usual binary file, when we are running Linux or Windows or create a directory structure with binary on its deepest level, when running OSX. CMake allows to do it in a really easy way:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (APPLE)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} MACOSX_BUNDLE ${SOURCE_FILES})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add_executable</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(${EXECUTABLE_NAME} ${SOURCE_FILES})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">endif</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span></span></code>

You should see something like this:

To end the process you may consider switching to a terminal and running

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pkill</span><span style="color:#40A02B;--shiki-dark:#A6D189"> irrlicht_newton_game1</span></span></code>

Understanding the code

Here are few simple things we could extract from application' code and understand right from scratch:

  • Each 3D model is a scene node

  • Primitive scene nodes (such as cube or sphere ) could be easily created with built-in functions:

    <code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addSphereSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ISceneNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addCubeSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>
  • Animated 3D models (such as character models ) could be loaded from file:

    <code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">scene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IAnimatedMeshSceneNode</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> node </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addAnimatedMeshSceneNode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getMesh</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"../../media/ninja.b3d"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span></code>

    Hint: if mesh is animated, animation could be started with:

    <code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setFrameLoop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 13</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAnimationSpeed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

    Hint: animation could be stopped with setting its speed to zero:

    <code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setAnimationSpeed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>
  • Node could be described not only by its vertices and indices (forming a set of triangles which are drawn in 3D forming a model, called mesh ) but by its position , rotation and scale

    Those could be set with:

    <code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setPosition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setRotation</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">x_angle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y_angle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> z_angle</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">node</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setScale</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">vector3df</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">width_factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> height_factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> depth_factor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span></code>

    Hint: rotation is a set of angles relatively to the corresponding axes, the node will be rotated around. E. g., vector3df(45, 90, 0) sets the rotation by 45 deg around X axis , 90 deg around Y axis and no rotation aroung Z axis . All those axes are relative to the node itself.

  • Graphics User Interface' (GUI) widgets for information output are labels; they are created with GUI Manager :

    <code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">gui</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IGUIStaticText</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> label </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getGUIEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addStaticText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">L""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> core</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rect</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">s32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">>(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 400</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span></code>

    Hint: its text could be set with:

    <code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">label</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> wchar_t</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "some text"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>
  • User input is handled by an external IEventReceiver class object.

    Its method,

    <code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">virtual</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> bool</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> OnEvent</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> SEvent</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

    defines the logic of handling events like mouse events , keyboard events , joystick events , GUI events , etc.

    The type of event is passed with the event.EventType field. The corresponding field is filled with the event parameters.

    For example:

    <code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">type </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> EET_MOUSE_INPUT_EVENT</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
    <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isLeftPressed</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
    <span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"%d, %d is cursor position</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">X</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> event</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">mouseInput</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
    <span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
    <span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

    Hint: EventReceiver object has nothing in common with our main game loop. So we should create some interface, some architecture trick to link those two. Because they are strongly related!

  • Main game loop should contain rendering call , GUI rendering call and other game logic processing calls.

    The simplest main loop could look like this:

    <code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">beginScene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> video</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">SColor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 113</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 113</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 133</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    smgr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // draw the 3d scene</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getGUIEnvironment</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">drawAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // draw the gui</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    driver</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">endScene</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
  • There is no simple (or at least, built-in) way to get the delta time between two rendered frames. This is an important variable! We'll need that later, when we inject physics engine. And Newton GD is not the only engine requiring this variable!

    But that could be easily done with this workaround:

    <code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// before main loop</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">u32 then </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTimer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// ...</span></span>
    <span class="line"></span>
    <span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// within the main game loop</span></span>
    <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> u32 now </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> device</span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTimer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
    <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">const</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> f32 frameDeltaTime </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">f32</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">now </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> then</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> /</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1000.f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // delta time in seconds</span></span>
    <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">then </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> now</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

That was some short introduction to the Irrlicht engine. And that's basically everything we will use for the next few sections.

Next chapter

Irrlicht Newton GD tutorial: application architecture urn:uuid:3cc0a858-68d0-55b3-956e-b72e65bc4816 2015-08-26T00:00:00Z 2015-08-26T00:00:00Z Irrlicht Newton GD tutorial: application architecture Artem Shubovych

Basic terms

Let's talk a bit about our application before we create it. In order to make the development process sequential and least painful, we need to design the application well. The design of an application or the application architecture is the hardest thing to change on later stages of development. Thus it must be well-thought at the very beginning to prevent suffering in the future.

Well, there are number of application architecture' levels:

The highest level defines which modules will the whole application consist of and what functionality will each of those modules have.

<code>    &#x3C;p>
        The next level is how the modules communicate to each other, how they work together.
    &#x3C;/p>

    &#x3C;p>
        The lower level is the structure of each module - what classes, entities, data structures and similar things will
        the module consist of.
    &#x3C;/p>

    &#x3C;p>
        One of the lowest, yet still very important architecture levels is how files are organized.
    &#x3C;/p>
&#x3C;/div>
</code>

From the highest architecture layer point of view, I can advice a very simple architecture:

  • a stable, rarely changed core
  • a set of assets (models, textures, sounds - any content, made by artists and used to be presented to the player)
  • a bunch of scripts , defining all the logic of a game (how character looks like, how the menus are shown and how they react to player’s actions)

The main benefits of such an approach are:

  1. scripts and assets may be changed at any time
  2. scripts and assets define what we show to the user and how the application behaves, so we can changes them without the need to re-compile the core
  3. we can modify the core (for example - optimize some features) without changing the application behaviour

We can make the core so flexible that we may re-use it in the future projects.

The tools

We will use Irrlicht engine because of its simplicity. And it satisfies all our needs - it does not need much content preparation; it provides GUI; extending it with IrrKlang will give us very simple interface to sound and music playback.

Newton Game Dynamics engine we will use to simulate physics. It is easy to use and is really powerful - you would be impressed!

The last, not the least, we will use Lua scripting language to write scripts. Lua is a lightweight programming language and perfectly suits that goal.

One of the most beautiful parts of this tutorial, will be the part on making of assets . We will use Blender 3D to create a couple of 3D models.

I also found CMake kind of user-friendly. It is not that handy as any of dependency managers for all those languages, supporting them ( npm for JavaScript, go get for Go, RubyGems for Ruby, leiningen for Clojure and many others) . Yet it makes your project a little more portable, helps to handle your dependencies, totally eliminates the need of all those How to configure VisualStudio for OGRE tutorials. Just try it!

Conclusion

Remember all the three rules for our architecture. And keeping them in mind, let's get to some coding already!

Next chapter

Irrlicht Newton GD tutorial: introduction urn:uuid:86ccf36b-06c2-50f8-a5b5-00ddcb403f5e 2015-08-25T00:00:00Z 2015-08-25T00:00:00Z Irrlicht Newton GD tutorial: introduction Artem Shubovych

What will you learn?

This tutorial covers the development of a game from a very beginning. This includes:

  • planning the architecture for a game
  • developing the game engine
  • defining game logic with scripts
  • creating 3d models
  • and distributing the application

And of course, the whole tutorial is built around Irrlicht and Newton Game Dynamics libraries.

As for {{ site.time | date: '%d %b %Y' }} , the tutorial covers:

  • an introduction to NewtonGD
  • creating Irrlicht-powered application
  • controlling the application logic with Lua scripts
  • building application with CMake

Why writing everything from scratch? Why not use Unity / Unreal Engine / you-name-it ?

There are some well-known and used game engines like Unreal Engine 4 , Unity 3D and others. They all come with enormous amount of learning materials. So why this tutorial might be interesting for you? You might want to know how things work and thus get most flexibility out of your tools. Or even start working on building your own tools.

What should I know to proceed?

I expect you to have at least some experience with these three things:

  • C++
  • computer graphics
  • game development

The latter - to make sure, you will not call 3d models “textures” or miss the “script” word’ meaning.

Why these libraries?

Irrlicht is easy to use and contains all the features you will need to build a game - resource management, support for majority of asset formats out-of-the-box, user input (keyboard, mouse and joystick events handling), GUI (Graphical User Interface - buttons, text inputs, etc.).

Irrlicht is easy to use and contains all the features you will need to build a game - resource management, support for majority of asset formats out-of-the-box, user input (keyboard, mouse and joystick events handling) , GUI (Graphical User Interface - buttons, text inputs, etc.) .

Newton Game Dynamics is also very easy to use; it is constantly developed; and it is darn powerful!

If you are still interested - please proceed to the first chapter .

ReactJS introduction urn:uuid:d9748cf4-f7c9-5ed2-a1a4-8eb5a99b2f82 2015-07-12T00:00:00Z 2015-07-12T00:00:00Z

Foreword

Last time I wrote an article on how one can encapsulate both HTML and CSS in one entity, called WebComponent. This time I want to tell a bit about how to encapsulate JavaScript and HTML.

When I see an article on Habrahabr titled React something , I think Omg, React again?.. . But React, just as Ember was always a mystery for me.

Until today.

Artem Shubovych

Foreword

Last time I wrote an article on how one can encapsulate both HTML and CSS in one entity, called WebComponent. This time I want to tell a bit about how to encapsulate JavaScript and HTML.

When I see an article on Habrahabr titled React something , I think Omg, React again?.. . But React, just as Ember was always a mystery for me.

Until today.

I've read an awesome article, React.js Introduction For People Who Know Just Enough jQuery To Get By . And now I really see the power of React. Though, I am still planning to play with Angular 2.0 and still remain a fan of Angular, I can tell you for sure, React may help you to raise your level if you are still writing your web-sites with jQuery.

React is a way to make your project consist of a components. So, for example, you have a complex webpage. You may then have a layout, styled in a way to support different themes. Then you may split all its partials into components, so you do not need your layout to hardly rely on its partials.

Although building components with react may seem polluting your code with HTML, it is really great concept to keep your HTML code near the JS code handling it. React has its own restrictions for the components. For example, you can not use two tags alongside inside your component. It is required to use exactly one top-level tag. And all the variables are stored in the state variable. But I will tell you how to overcome that restriction later.

The architecture

This article relies on JavaScript, so let's be kind and create an initial project structure for a typical JS project. Just like this:

Project structure

This is always great to have a typical structure for a project so anyone new to the project will not get lost.

So, we can assume we will always have a set of javascripts and stylesheets, used on a front-end. We also may need some third-party libraries, managed by NPM or Bower. And this is always (I mean not javascript projects only) a great idea to have your changes being tracked by some version control system. I like Git the most.

Based on those few assumptions, we will need a folder with javascripts and stylesheets sub-dirs; .gitignore , package.json and bower.json files (select those you need) .

In some cases, like with this article, we may need to compile some of resources. For that purpose we may create something like build directory. And define the build command in package.json file, within the scripts section.

A very simple introduction

Preparing layout template

So, let's start writing a layout for our sample webpage. This may be done with Emmet . Just type html:5 and press Tab within your favorite text editor (I feel comfortable with both Sublime and Atom, yet you may run Emacs and still use Emmet) .

Front-end dependencies

Now, let's add bootstrap and react scripts. The good way of doing it is using bower . Now there are two ways of adding dependencies with bower: manually editing bower.json or using command-line.

If you decided to add dependencies into bower.json file, remember to set the concrete versions for each dependency. Or you may face situations, when someone installs your project and uses the newer versions of libraries, which are incompatible with the code, which uses them.

Here are the lines you will need to add to your bower.json file to proceed:

<code><span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">  "dependencies"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "react"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "0.13.3"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "bootstrap"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "3.3.5"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span></code>

If you have chosen the CLI way, consider this command:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  bower</span><span style="color:#40A02B;--shiki-dark:#A6D189"> install</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --save</span><span style="color:#40A02B;--shiki-dark:#A6D189"> bootstrap</span><span style="color:#40A02B;--shiki-dark:#A6D189"> react</span></span></code>

I preferred the CLI way as it chooses the correct libraries' versions automatically.

Now you may add React's javascript and Bootstrap's CSS into the layout:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  &#x3C;!DOCTYPE</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">meta</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> charset</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"utf-8"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">title</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Introduction to ReactJS</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">title</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> src</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bower_components/react/react.min.js"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x3C;</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">link</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> href</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bower_components/bootstrap/dist/css/bootstrap.min.css"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"stylesheet"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text/css"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

First NPM task

You may want to add a task to your package.json to install bower dependencies automatically:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">dependencies</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">bower</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "1.4.1"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "scripts"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">bower</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "./node_modules/bower/bin/bower install"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span></code>

This may be useful later, when building a project. Here I used the local version of bower in the script to not make another project requirement of globally installed bower. This approach is used lately in this article for building task.

JSX vs JavaScript

React uses JSX . JSX has two meanings. Accordingly to List of languages that compile to JS , JSX is an extension of JavaScript with human-friendly OOP and type safety support. In the universe of React, JSX is an extension of JavaScript too. But in this case, JSX only allows to create DOM elements from within the code in a DSL-style.

To explain what is DSL-style, I shall show you two examples:

non-DSL way:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"div"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">className</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "well clearfix"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"textarea"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">className</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "form-control"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> onChange</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handleChange</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"br"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createElement</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"button"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">className</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "btn btn-primary pull-right"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">},</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Tweet"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span></span></code>

DSL way:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"well clearfix"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"form-control"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onChange</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">handleChange</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">br</span><span style="color:#179299;--shiki-dark:#81C8BE">/></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"btn btn-primary pull-right"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tweet</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Both of JSX branches are, again, extensions to JavaScript, thus they need to be compiled to ES5 (also known as “usual javascript”) to make the code understood by browser. For this purpose we need a compiler. For React this is called react-tools . So let's add it as a dependency inside our project's package.json file. This will add the jsx utility to the node_modules sub-dir. So we may define another build task within the package.json file:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">scripts</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      "</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">build</span><span style="color:#7C7F93;--shiki-dark:#949CBB">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "./node_modules/react-tools/bin/jsx src/javascripts/ build/"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span></code>

This task compiles all the scripts from the src/javascripts/ directory and stores the compiled javascripts in build/ directory.

First component

All components are made simply calling React.createClass() method and providing it with a component's rendering method (a method that returns component's HTML) , its initial state (something like Angular's $scope ) and event handlers. Just check it out:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> TweetBox </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createClass</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    render</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"well clearfix"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"form-control"</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">br</span><span style="color:#179299;--shiki-dark:#81C8BE">/></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"btn btn-primary pull-right"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tweet</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Here you may see a few restricts, done by React:

  1. you need **exactly** one top-level tag for your component
  2. you may not use class attribute within elements, use className instead
<code>
  React.render(
    &#x3C;TweetBox />,
    document.body
  );
</code>

Note: you may not use the &#x3C;TweetBox /> tag from within the HTML.

Now let's write that component within the javascripts/app.js file and reference it in the layout, at the end of &#x3C;body> tag; to make it loaded when all the document is done loading:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  &#x3C;!DOCTYPE</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> html</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">meta</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> charset</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"utf-8"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">title</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Introduction to ReactJS</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">title</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> src</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bower_components/react/react.min.js"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x3C;</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">link</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> href</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bower_components/bootstrap/dist/css/bootstrap.min.css"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"stylesheet"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text/css"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">head</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> src</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"build/app.js"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x3C;</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">body</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

To see the page we've written in action, first compile the sources with npm run build to compile the JSX code to javascript and use it in the layout template.

State

The component's internals are stored within the state variable. This is something like Angular's $scope . React adds a method to initialize your component's state, called getInitialState() . It should return object, representing the initial state. State variables may be accessed via this.state.myVar and interpolated in template with curly-braces syntax, {this.state.myVar} . So you may do something like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> TweetBox </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> React</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createClass</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    getInitialState</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        text</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        maxLength</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 140</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    render</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"well clearfix"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"form-control"</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">br</span><span style="color:#179299;--shiki-dark:#81C8BE">/></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">span</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxLength </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#D20F39;--shiki-dark:#E78284"> this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">length </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">span</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">          &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> className</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"btn btn-primary pull-right"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tweet</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      )</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

State may be changed with the setState() method, receiving… object! But this time, the object for setState() represents a set of new field values. So, for example, using syntax

<code><span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">  this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setState</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "newValue"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

will not replace the whole state with text field only. Instead, it will modify text field only and will left maxLength unchanged.

But when can we call the changeState() ? In Angular it is done with data binding . But in React we have events. Yes-yes, simple DOM events!

So, for example, we may set the onChange event in the &#x3C;textarea rows="10" cols="50"> and just handle it:

<code>  var TweetBox = React.createClass({
    ...
    handleChange: function(evt) {
      this.setState({ text: evt.target.value });
    },
    render: function() {
      ...
      &#x26;lt;textarea className="form-control" onChange={ this.handleChange }&#x26;gt;
      ...
    }
</code>

Yeah, looks not so pretty as with Angular…

React: conclusion

I assume React's way of doing websites is nice until you learn something better. At least, when switching from jQuery, you can make your webpage's code look much better with React!

Alternatives

Riot

But wait! There are alternatives! Riot continues React experience of state. But makes it with a much more pretty code. But the main advantage of Riot is ES6. Yeah, when both of libraries use compilation, why reject the future and invent a wheel? Thus Riot makes your code much more clear. Check this out:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">tweet-box</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"well clearfix"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"form-control"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> onkeyup</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> handleChange</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> }</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">textarea</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">br</span><span style="color:#179299;--shiki-dark:#81C8BE">/></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">span</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">{ maxLength - text.length }</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">span</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"btn btn-primary pull-right"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Tweet</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">button</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">      this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">      this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxLength </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 140</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      handleChange</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(evt) </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> evt</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">target</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    &#x3C;</span><span style="color:#179299;--shiki-dark:#81C8BE">/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">tweet-box</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

Everything looks great with Riot: its size is much more lower than React's; it has ES6 and nice syntax; it does not turn your JS code into substance on the edge of two worlds - views layer and logic layer ; it has even scoped css !..

But Riot has one huge drawback. That drawback is XHTTPRequest . By default, you may define your components inline, just within your layout page. But as long as it is a mix of HTML and JS, browser will not correctly respond to your page, throwing you strange exceptions. So, you may decide to extract your components into separate files. But here you may face the fact that most of modern browsers do not allow for asynchronous requests to the files without protocol being provided (so you can not load project files via AJAX while testing project locally) . And that's how Riot loads your components - via AJAX. So you need either to pre-compile your components or run your project on a web server.

Angular 2.0

Great news for each and every AngularJS fan; the essence of future of web development, Angular.js 2.0 . It is made with TypeScript , which is even more powerful than ES6. It provides developers with component architecture - HTML and JS encapsulation, but in even more sophisticated form.

So, for example, our <tweet-box> component in Angular 2.0 may look like this:

tweet-box.ts:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  ///</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">reference</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#40A02B;font-style:italic;--shiki-dark:#A6D189;--shiki-dark-font-style:italic">../typings/angular2/angular2.d.ts</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  import </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Component, View, bootstrap, formDirectives</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> from </span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#40A02B;--shiki-dark:#A6D189">angular2/angular2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  @Component</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    selector</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> '</span><span style="color:#40A02B;--shiki-dark:#A6D189">tweet-box</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  })</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  @View</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    directives</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">formDirectives</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    templateUrl</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> '</span><span style="color:#40A02B;--shiki-dark:#A6D189">src/tweet-box.html</span><span style="color:#7C7F93;--shiki-dark:#949CBB">'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  })</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TweetBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    text: string</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    maxLength: integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    constructor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">      this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">maxLength </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 140</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">      this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ''</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  bootstrap</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TweetBox</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

tweet-box.html:

<code class="language-mustache">
  &#x3C;div class="well clearfix">
    &#x3C;textarea class="form-control" [(ng-model)]="text">&#x3C;/textarea>
    &#x3C;br/>
    &#x3C;span>{{ maxLength - text.length }}&#x3C;/span>
    &#x3C;button class="btn btn-primary pull-right">Tweet&#x3C;/button>
  &#x3C;/div>

</code>

Here, as you can see, data binding is used, so there is no more need in event handling. And you can use all the power of TypeScript. But still, the great Angular 2.0 drawbacks are:

  • Angular 2.0 is still on the alpha stage (at least, while I am writing this post, it is)
  • too much effort is needed to get it working (because of p. 1; still, THREE dependency managers to get it work is way too much…)
  • it still needs the server to serve templates or using templates inline
  • there are some major differences with all of the other libs referenced here, which may be hard to get used to (for ex., using formDirectories like [(ng-model)]="modelName" )

Fin

Looking at those three libraries, I can tell that Riot made my day. It is as simple as powerful and small. It lacks for two-way data binding, but makes much more sense than React. And yet does not require you to get mad installing all those dependencies to make it work.

All the examples, mentioned in the article are on my GitHub account:

About Bower, WebComponents and the all the good urn:uuid:2676ea9d-70c8-5bdd-bd63-0a60735ca952 2015-06-22T00:00:00Z 2015-06-22T00:00:00Z

BEM

These days, many web developers use different methodologies to make their web page source look structured and clean. But all those methodologies only work well until you use third-party libraries or involve a new person in your project.

Artem Shubovych

BEM

These days, many web developers use different methodologies to make their web page source look structured and clean. But all those methodologies only work well until you use third-party libraries or involve a new person in your project.

BEM (Block Element Modifier) is a convention for naming CSS classes in a such way so they do not overlap. Doing so you may turn your page into a set of independent blocks, or components . According to BEM, you name your CSS classes as follows: BlockName__ElementName__ElementModifier .

BlockName is a name of a component , your element belongs to. This may be a menu, a gallery or a widget, for example.

ElementName is a name of element of the block. Good examples of elements are label, title, avatar, menu_item, etc.

ElementModifier is a more complex thing. This is a state of element, which defines how element may look like in a certain conditions. This may be a checkbox' checked status, focus property or is_menu_opened flag. Modifier may have one of two types:

  • boolean , where modifier is just a flag, showing if element's property is active or not
  • key-value , where modifier points to one of many possible property values

For example, boolean modifiers are: checked , big (is element big or not), hovered , opened , etc. Key-value modifiers may be, for instance, menu_type_bullet or menu_type_numbers , menu_top , menu_left or menu_right (representing menu' position).

Combining those three you may determine the look of any element and its state:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">navigation__menu__position_left</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">...</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">navigation__menu__position_right</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">top_menu__avatar__small</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">top_menu__avatar__medium</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/* more meaningful */</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">user_widget__avatar__menu_position_top</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">user_widget__avatar__menu_position_left</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">user_widget__avatar__menu_position_right</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/* more simple */</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">button__big</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">button__red</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ... </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

The aim of BEM is great - to make the web page use independent blocks with some structured CSS class names and have them all described in a nice way in the CSS files. Whilst it may sound like a Holy Grail for the Web, let's take a look at a real-world example of how BEM is used.

There are, in fact, two approaches of BEM.

The old approach

Below is an example of vanilla BEM:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">bwelcome__message</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">hidden</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> none</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">bwelcome__message</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    color</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> yellow</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    border-radius</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    text-align</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> center</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">bwelcome__label</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    font-size</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 12</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">pt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">bwelcome__input</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    display</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> block</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">    width</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 100%</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And the HTML:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bwelcome"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bwelcome__message hiddent"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Hello, username!</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bwelcome__label"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Enter your name:</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bwelcome__input"</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

So, here we can see that any styles should not overlap with the defined ones unless they are written in a BEM-way for the same element. Nice idea,implementation not so nice… All these b#{block}__#{element} classes are way too long, don’t you think? Writing them everywhere - HTML, CSS and JavaScript - is really painful.

The new approach

But what about the newer version of BEM? Its authors developed a toolbox with their own framework, containing many tools to help you use BEM methodology. It contains two interesting tools - BEMJSON and BEMHTML . Those two allow you to define your views with JavaScript and JSON.

To use them, just install bem with npm : npm install bem . Then you will be able to create your pages with either BEM, BEMTREE, BEMHTML and BEMJSON. This has two advantages to writing pages by your own:

  1. they come with plugins, so you may have some parts of CSS ready to use out-of-the-box
  2. it replaces writing all the selectors manually with writing them via commands of the bem utility

For instance, here's how your page may look like when being made with BEMHTML:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     block</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'page'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     title</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'hello'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     head</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">         {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elem</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'css'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '_hello.css'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     ]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     scripts</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> elem</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'js'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> url</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '_hello.js'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     mods</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> theme</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'islands'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> },</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     content</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">         {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">             block</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'hello'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">             content</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                 {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                     elem</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'greeting'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                     content</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Hello, %username%!'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                  }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">             ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">         }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">     ]</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

And here's how it may look like when made with BEMJSON:

<code><span class="line"><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic">exports</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">deps </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "block"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "page"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "elem"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "css"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "attrs"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "src"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "_hello.css"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "block"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "page"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "elem"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "js"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "attrs"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "src"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "_hello.js"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "block"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "page"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "elem"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "meta"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "block"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "header"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "block"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "content"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    },</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    {</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "block"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "footer"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Those two may work both together, when you define general page structure with BEMJSON and each block you define with BEMHTML, or separatedly, when you define all your page in either BEMJSON or BEMHTML.

But anyway, in BEMJSON or BEMHTML or whatever, the whole page is described in one JS file, which will then be compiled into an HTML page. Using this approach allows you not only to pack the blocks and elements into one structure, but also to spice it up with some JavaScript, which handles those components.

Sounds great and may be somewhat helpful for new projects. But I believe there's a better solution.

Introducing WebComponents

Although the implementation of BEM is clumsy, the idea is really great! This is just like encapsulation in OOP - one of the mightiest principles in programming. But what better options are there than BEM?

Recently we have all seen great changes to the Web. We now have ES6, CSS3, HTML5 and all of them give us ultimate power! Support for old browsers is now provided with hacks called polyfills . But why should we stop ourselves using the best of what we have in the name of 3% of Internet users ? Well, if you really do have to continue supporting all of those, you could just stop reading now. Or you could concentrate all your will and try out all these brand-new features in your pet project.

So, the new approach in web design encapsulation uses WebComponents. This is a technology, which does not works everywhere. This is contraversary to a BEM methodology, where you only define a CSS classes, which are supported since very early CSS versions.

So, welcome the WebComponents' example:

<code><span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">template</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"welcome-component"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">style</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          background-color</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fea</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          padding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          text-align</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          border-radius</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          font-family</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Arial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">style</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"message"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Hello, {{</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">}}!</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">template</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"shadow-host"</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"message"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Non-component message</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> type</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"text/javascript"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> host </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.shadow-host'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        template </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> document</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'#welcome-component'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        shadow </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> host</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">createShadowRoot</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    shadow</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">appendChild</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(template</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">content)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span></code>

This code may not look so good, as it might, but it works like a charm!

image

This example is a bit ugly - it has both CSS, HTML and JavaScript mixed in a single file, but we’ll deal with it for a short time. Just think of the power you’ve got! You can define your own… well, it’s certainly kinda components! It is a bit uncomfortable to paste onto a page… and they are hardly ready to be used with something like Angular.

Well, yeah, this is as ugly as BEM.

But now you defined a component of your web-page, which you can then reuse with copying just one portion of XHTML in place. And placing it inside a totally different web page will not break it down - both HTML and CSS are separated and isolated and will not overlap with any other style or martkup. But let’s try out our web component!

Bower

Earlier I did not need to use any package managers except gem and apt-get . Yet, I was not so stupid as to install all the javascript libraries my project needs with RubyGems. On my projects I had to download the necessary library versions and store them in the assets/javascripts directory. Forever. Or at the very least an upgrade was needed.

But then I tried Bower. It was so easy to manage my assets! So I highly recommend this way to you, dear Reader!

To use Bower from scratch on a brand new project, you need to

  1. install Bower with npm
  2. ininitialize your project with bower init
  3. define dependencies in the dependencies object in your new bower.json file
  4. install them with bower install

Then you should end up with all your libraries in the bower_components directory. And that’s it! Every package has its own dir. So you can keep track of all the versions etc.

Polymer

Let’s start cooking our demo with Polymer . First, initialize the Bower project and add this section to your fresh bower.json file:

<code><span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">"dependencies"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    "polymer"</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Polymer/polymer#^1.0.0"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Then run bower install . This will provide you with all the stuff you need.

Now we will move our pretty welcome-component to a new place. Create two files: welcome-component.html and index.html . Fill the last one with Emmet :

<code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">html:5</span></span></code>

(you need to hit the “Expand” key, formerly Tab, at the end of this single line while editing the index.html file in an Emmet-powered editor) . And add just a single line within the HTML’ &#x3C;body> tag:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">welcome-component</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">welcome-component</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

Now let’s define our new component in welcome-component.html :

<code><span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE"> &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">dom-module</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> id</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"welcome-component"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">style</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        .</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">message</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          background-color</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> #</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">fea</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          padding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 10</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 20</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          text-align</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> left</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          border-radius</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">px</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">          font-family</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Arial</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">style</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">template</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"message"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">Hello, {{ </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> }}!</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">      &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">template</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      Polymer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        is</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "welcome-component"</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">script</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">  &#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">dom-module</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span></code>

Now, add our new component importing to the &#x3C;head> tag of the index.html file:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">link</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"import"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> href</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"bower_components/polymer/polymer.html"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> &#x3C;!-- imports Polymer --></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">link</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> rel</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"import"</span><span style="color:#DF8E1D;--shiki-dark:#E5C890"> href</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"welcome-component.html"</span><span style="color:#179299;--shiki-dark:#81C8BE"> /></span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> &#x3C;!-- imports our component --></span></span></code>

To run this quickly, you might want to use http-server from npm :

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">http-server</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> --cors</span></span></code>

And voila! We’ve just made a nice web component, which could be used really simply. And the code is totally clean!

If you look at the HTML source, you’d see a beautiful DOM structure: we’ve got our &#x3C;div class="message"> within the &#x3C;welcome-component> tag. And its style will never affect any other elements, even when you create another &#x3C;div> outside the &#x3C;welcome-component> . Seriously, you can try it!

Yeah, I know we’ve used Polymer and that’s cheating. But think of it as of a temporary hack you will remove when your browser starts supporting custom tags.

Custom attributes for custom tags

Now, the last thing I’d like to show is the attributes for our custom components. We’d like to pass some data to our brand new components easily, right? So, let’s define a name attribute, which we’ll show instead of it!

To do this, we shall use two Polymer features. First of all, let’s define our attribute, adding this section to our Polymer() call:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Polymer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ...</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    properties: </span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      name</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        type</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> String</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">      }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Now that we’ve defined our attribute THAT simply, we should use it somehow. Polymer allows us to define a method, which will be called once the component gets inserted into a webpage:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Polymer</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ...</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ready: </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">      this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">querySelector</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'.message'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">innerHTML </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> `Hello, </span><span style="color:#7C7F93;--shiki-dark:#949CBB">${</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#179299;--shiki-dark:#81C8BE">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">!`</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

As long as you're riding IOJS NodeJS 5.0+, you can use the ES6 string interpolation feature, as in the example above =) Here, the this variable is bound to the &#x3C;welcome-component> tag. So in order to change the .message tag's HTML, we need to find it first. For this purpose I’ve used the HTML5 querySelector method.

Cool enough, right?

Conclusion goes here

To end-up this short tutorial on WebComponents, I would like to suggest you to read some other tutorials, especially the WebComponents website . And never stop trying something new!

Memory allocation in ASM urn:uuid:de100af5-cff0-57e6-891b-6cb34cdea3af 2015-05-06T00:00:00Z 2015-05-06T00:00:00Z

Currently I am working on a long arithmetic problem at the university. This problem is much more complicated than I described or than a task I shall be describing now, but here’s the thing: I needed some part of memory to be allocated from within my function. And I needed this to be done in assembly.

Artem Shubovych

Currently I am working on a long arithmetic problem at the university. This problem is much more complicated than I described or than a task I shall be describing now, but here’s the thing: I needed some part of memory to be allocated from within my function. And I needed this to be done in assembly.

Thus, I created this piece of snippet code:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; void addition(int* x, int x_len, int* y, int y_len, int* &#x26;z, int* z_len);</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">global _Z8additionPiiS_iRS_S_</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z8additionPiiS_iRS_S_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p_x [ebp + 8]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x_len [ebp + 12]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p_y [ebp + 16]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y_len [ebp + 20]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p_z [ebp + 24]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> p_z_len [ebp + 28]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addition_allocate_mem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; push x_len * 4 ; bytes to allocate</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> * </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; bytes to allocate</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    call</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> malloc </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; call malloc()</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add</span><span style="color:#D20F39;--shiki-dark:#E78284"> esp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; undo push</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; save returned address from malloc</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, p_z</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">edx</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; z = malloc(...)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, p_z_len</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">dword</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; *z_len = elements</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">addition_fill_mem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; fill with sample values</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, p_z</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> * </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">dword</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; mov eax, p_z</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> * </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">dword</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; mov eax, p_z</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; add eax, 2 * 4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> * </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">dword</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

There are, however, a few really interesting things in this code:

  • naming of C++ functions, generated from assembly (name mangling)
  • memory allocation itself
  • returning data from function via pointers… in assembly!

To demonstrate how this stuff works, we need some C++ code which uses our assembly function:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdio.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdlib.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// our addition function for BIG integers</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// arguments are as follows: number and its length; two first pairs are the operands</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// and the last two arguments describe the returned big integer</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// thus, the result is z = x + y</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extern</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "C"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> addition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> y_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> z_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// helper function to convert BIG integers to strings</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">char*</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> bigint2str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    char</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> malloc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">i</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\0</span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a_len </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // here we add nothing with nothing</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // and storing the result in a big integer `a`</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    addition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"a = %s</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> bigint2str</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Comments in the code describe those moments which are important.

To compile these codes and link them into one executable, use these:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> nasm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -felf32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test.asm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_asm.o</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test.cpp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -c</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_c.o</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_asm.o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_c.o</span></span></code>

Now, let’s talk about name mangling. It is really important. I shall not cover all the depths of this, only the parts, related to this article.

We see that our function,

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> addition</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> y</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> y_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">z</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> z_len</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

is known as _Z8additionPiiS_iRS_S_ in the assembly code.

What’s the..? What are all these strange prefixes? - you might ask.

Here’s the convention:

  1. functions are named with the underscore and an uppercase letter
  2. function name’ length and the name itself follows that prefix
  3. arguments are stored as their types only

Argument type is encoded as well. For our example, we see these:

  1. Pi - that means, literally, pointer to integer
  2. i - that stands for integer
  3. S_ - that is the same as Pi , equal to signed integer , but for some reason (yes, I do not know why this happens) if you try to replace it with Pi , your function will not be found by a linker
  4. RS_ - this is a reference to a pointer to integer

To get know those conventions better, you might refer to g++ internals reference .

You can decode demangled (encoded) function names as well. Just use c++filt utility:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> c++filt</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -n</span><span style="color:#40A02B;--shiki-dark:#A6D189"> _Z8divisionPiiS_iRS_S_</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">division(int*,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> int,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#40A02B;--shiki-dark:#A6D189">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> int,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">&#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span></code>

‘til next time!

Assembly in C++ programs urn:uuid:28117ba7-7729-5a9b-ae8d-75e7af352d1d 2015-04-23T00:00:00Z 2015-04-23T00:00:00Z

Foreword

Writing code in assembly language in 2015 seems stupid and meaningless. Yet, it has a few huge benefits:

  1. understanding how computers / compilers / programs work
  2. hardcore optimizations for performance-critical applications
  3. just for fun!

Well, in real life, I’ve never met conditions of such performance requirements when I should be writing some parts of application in ASM. Except, maybe, a handful of ACM ICPC problems.

Those are two merely big benefits to write in assembly. Thus, if you are not getting fun out of coding, you may not be interested in this blog.

This blog is mostly for academical purposes. People who study something like low-level programming at the university may be interested.

Artem Shubovych

Foreword

Writing code in assembly language in 2015 seems stupid and meaningless. Yet, it has a few huge benefits:

  1. understanding how computers / compilers / programs work
  2. hardcore optimizations for performance-critical applications
  3. just for fun!

Well, in real life, I’ve never met conditions of such performance requirements when I should be writing some parts of application in ASM. Except, maybe, a handful of ACM ICPC problems.

Those are two merely big benefits to write in assembly. Thus, if you are not getting fun out of coding, you may not be interested in this blog.

This blog is mostly for academical purposes. People who study something like low-level programming at the university may be interested.

Simplest function in NASM

And to start off, we will write a very simple program in assembly language. I shall be covering NASM language and compiler under Linux. MASM for Windows is much like that, but you should find your own way of compiling, linking and debugging all this code.

Our first program will do nothing. It will just contain globally available function, named myfunc .

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    BITS </span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    section .text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        global myfunc</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    myfunc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        ret</span></span></code>

This is barely a something useful, but that’s how it looks like. A simple function, which does nothing, has no arguments and returns nothing.

Note these instructions: enter 0, 0 and leave . These are dedicated to create a stack frame . Stack frame is a part of stack, where we can store variables. This part of stack is isolated, so we barely may hurt system when using stack operations ( push and pop ).

Actually, you may create the stack frame yourself, pushing ESP and EBP to a stack manually, then shifting ESP and rolling all this back at function’s end. But these instructions are simpler.

NOTE: never forget the leave operation when using enter one! This may cause a SEGFAULT exceptions and you may spend hours searching for an error (just as I did this night…) .

To use our function in a C++ program, we need to perform three steps:

  1. add en external declaration for our function in C++
  2. compile our C++ and NASM programs to object files ( .o or .obj)
  3. link our object files into a single binary one

So, we need to interference with assembly from within our C++ code. And declare an external function. Here’s how our dummy program may look like:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdio.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extern</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "C"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> myfunc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    myfunc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Compiling this contains three steps, as I mentioned above:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -c</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test.cpp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_c.o</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> nasm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -felf32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test.asm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_asm.o</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_c.o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_asm.o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test</span></span></code>

Let’s take a look over each of these closely.

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -c</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test.cpp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_c.o</span></span></code>

This tells compiler a few things:

  1. -c : only compile the code, do not link it (do not search for referenced functions)
  2. -m32 : compile code in a 32-bit mode
  3. -g : add a debugger information
  4. -o test_c.o : write output to a test_c.o file

Why 32-bit mode? Why not 64-bit? - you may ask. Because some conventions of 64-bit mode are harder to understand and should be compared to 32-bit ones.

Now, compiling assembly code command:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> nasm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -felf32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test.asm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test_asm.o</span></span></code>

This provides compiler with these options:

  1. -felf32 : compile in a 32-bit mode
  2. -g : add a debugginng info
  3. -o test_asm.o : write output to an object file test_asm.o

Note the difference between -m32 and -felf32 . They mean the same, but are spelled differently.

Passing arguments and returning values

Now let’s make our function do something for a great good. For example, sum-up two numbers. We will end-up with this function declaration:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extern</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "C"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum_two_numbers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

The values a and b are integer. This means, each of them is 4-byte wide . You can find sizes of different C types writing a very simple program:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdio.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(char) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(short) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">short</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(int) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(long) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(long long) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(float) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(double) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">double</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(long double) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(char*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(short*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">short</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(int*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(long*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(long long*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(float*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(double*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">double</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"size(long double*) = %d bytes</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

On my laptop this code printed this:

<code>size(char) = 1 bytes
size(short) = 2 bytes
size(int) = 4 bytes
size(long) = 8 bytes
size(long long) = 8 bytes
size(float) = 4 bytes
size(double) = 8 bytes
size(long double) = 16 bytes
size(char*) = 8 bytes
size(short*) = 8 bytes
size(int*) = 8 bytes
size(long*) = 8 bytes
size(long long*) = 8 bytes
size(float*) = 8 bytes
size(double*) = 8 bytes
size(long double*) = 8 bytes
</code>

But when run in 32-bit mode, these numbers are different:

<code>size(char) = 1 bytes
size(short) = 2 bytes
size(int) = 4 bytes
size(long) = 4 bytes
size(long long) = 8 bytes
size(float) = 4 bytes
size(double) = 8 bytes
size(long double) = 12 bytes
size(char*) = 4 bytes
size(short*) = 4 bytes
size(int*) = 4 bytes
size(long*) = 4 bytes
size(long long*) = 4 bytes
size(float*) = 4 bytes
size(double*) = 4 bytes
size(long double*) = 4 bytes
</code>

The difference in atomic types seems really negligible, namely long and long double are 4-byte longer in 64-bit mode. But when it comes to pointer types, we have twice longer variables.

That is the first, may be not so notable, but really important difference between 32-bit and 64-bit modes. This will be handy when it comes to arrays . But that will be covered later.

Now, the more notable difference hides in how arguments are passed to a function and how the function returns its result.

To show this difference, we will write a few short functions and look at their assembly code. Here they are:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'x'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">short</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">short</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">short</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2147483647</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.14f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">double</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.15</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">double</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">double</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func13</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.16</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'x'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func8</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func10</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.14f</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func11</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func12</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func13</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    func14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">3.14</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Compile it with g++ using this command:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -S</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -c</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -masm=intel</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test1.cpp</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test1.asm</span></span></code>

I’ll explain this line’s options:

  1. -S : generate assembly output
  2. -m32 : generate 32-bit code
  3. -c : stop after compiling
  4. -masm=intel : use Intel’ assembly syntax; it is NASM’ syntax and thus more readable then GASM’ one
  5. -o test1.asm : write output to a test1.asm file

I shall not show the full output of this program, because it’s huge. It takes almost 400 lines of assembly code (370, actually)! Yet, in 64-bit mode it is just a bit more than 300 lines of code (precisely, 318). 60 LOC difference, but still…

These 60 lines of code is caused by a C type sizes. See, in 32-bit mode we have registers of a size 32 / 8 = 4 bytes. This is enough to store int or float value. Byt when it comes to long double or even just double , we have 4 bytes more. In 64-bit mode we have 8-byte wide registers. So, even a long double variable may be stored in a single register.

But let’s go back and take a look at, let’s say, func1 function assembly:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z5func1v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LFB0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .cfi_startproc</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    push</span><span style="color:#D20F39;--shiki-dark:#E78284">    ebp</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .cfi_def_cfa_offset </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .cfi_offset </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">esp</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .cfi_def_cfa_register </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">120</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    pop</span><span style="color:#D20F39;--shiki-dark:#E78284"> ebp</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .cfi_restore </span><span style="color:#FE640B;--shiki-dark:#EF9F76">5</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .cfi_def_cfa </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .cfi_endproc</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">LFE0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .size   _Z5func1v, .-_Z5func1v</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .globl  _Z5func2c</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    .type   _Z5func2c, @function</span></span></code>

Yeah, monstrous… Cleaning it up and using enter and leave , we have only this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z5func1v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">120</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

See, the return value is stored in a EAX register. That’s how we should return values from our functions. When it comes to a larger data types, we may return values via EDX:EAX registers’ pair. Yeah, strange, but that is a convention .

Let’s take a look at the assembly code for a func7 function and compare its variations for 32-bit mode vs 64-bit mode:

32-bit func7:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z5func7v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">2147483647</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

64-bit func7:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z5func8l</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">rdi</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">QWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">rbp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

See, there are two registers used in a 32-bit mode, EAX = 2147483647 and EDX = 0 . The second register is used for a sign value. If we’d change the return value for our C++ function to return a negative value:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> func7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2147483647</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

We will end-up with this code in a 32-bit mode:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2147483647</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span></span></code>

And in 64-bit mode it will have only one operation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> rax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2147483647</span></span></code>

Now let’s take a look over the func8 function:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z5func8x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    sub</span><span style="color:#D20F39;--shiki-dark:#E78284"> esp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DWORD</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PTR [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

We may clean it up removing all those DWORD PTR type hints:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z5func8x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    sub</span><span style="color:#D20F39;--shiki-dark:#E78284"> esp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">+</span><span style="color:#FE640B;--shiki-dark:#EF9F76">12</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">], </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">-</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

All the memory “by the negative side” of EBP is dedicated to local variables. All the memory “by the positive side” of EBP is the one with arguments, passed to our function.

Taking that into account, we may rewrite our assembly function as this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">_Z5func8x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x1 dword[ebp+8]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x2 dword[ebp+12]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmp1 dword[ebp-8]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmp2 dword[ebp-4]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    sub</span><span style="color:#D20F39;--shiki-dark:#E78284"> esp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">8</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, x1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmp1, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, x2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tmp2, </span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, tmp1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, tmp2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

Now it became more readable.

Here we have a few really important things:

  1. sub esp, 8 - this allocates 8 bytes of stack memory for our local variables
  2. [ebp+8] and [ebp+12] are two parts, each 4-byte long, of our argument of type long long
  3. [ebp-8] and [ebp-4] are two parts of our return value; each 4-byte long; of type long long
  4. return value is split into two registers, namely, EAX (high-order bytes) and EDX (low-order bytes)

That is how C passes arguments to a function in 32-bit mode. Arguments here are passed via stack. In 64-bit mode it’s a bit complicated: arguments are passed via registers and if they are not enough - through the stack. Registers are the following (ordered): RDI , RSI , RDX , RCX , R8 , R9 .

And the return values are stored in registers. Always. In both 32-bit and 64-bit modes.

Working wit arrays

I shall not cover working with arrays in NASM itself, but rather working with already allocated memory in C.

Arrays are transfered to a function as pointers in C and C++. Under the hood, pointer is just an address to a memory block. To its beginning, actually. Knowing the size of each array element and elements count , we may perform any kind of operations simply iterating through a set of memory addresses.

Let’s for example calculate a sum of an array elements:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdio.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extern</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "C"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 7</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 9</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> -</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // 1 + 2 + 7 + 9 - 4 = 15</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"sum(a) = %d</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

And let’s create the function sum in NASM. To start off, we’ll use a function, receiving two arguments, int and int* and returning a zero.

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">BITS </span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">global sum</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n dword [ebp + 8]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a dword [ebp + 12]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

Now what we would like to do is to add each element of array to our result variable (oh, we do not have one yet!) . To do this, we will use two registers: ECX to count how many elements we have added and EAX to store the sum. Each element’s address is *a + 4 * i or address of a[0] plus 4 bytes times i , our element number.

The loop we would use is a reverse one: first we assign ECX = n and then decrement our ECX by one each loop iteration. We are decrementing ECX by one because it contains a number of elements at the beginning of our function. We may use even reverse approach (or a straight one in the meanings of C, when we count from the first element to the last): first, we assign ECX = 0 and before going to the end of a loop we will compare ECX to n instead of zero.

In NASM we may calculate the address of each array element in the operand itself: [ebx + 4 * ecx] .

Now everything what we need is to add all those hints into a single program:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">BITS </span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">global sum</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sum</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n dword [ebp + 8]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a dword [ebp + 12]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; EAX = sum = 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ebx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, a </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; EBX = *a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, n </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; ECX = i = n</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add_loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> + </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> * </span><span style="color:#D20F39;--shiki-dark:#E78284">ecx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> - </span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; EAX += a[i]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    dec</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; ECX --</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    cmp</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_loop </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; if ECX &#x26;gt; 0 then goto add_loop</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; EAX contains the sum here</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

Note that I subtract four bytes in an element address: [ebx + 4 * ecx - 4] . That’s because our i'th element starts at *a + (i * 4) byte, but we have i = n on the beginning. Thus, first iteration will try to add element, starting at *a + (n * 4) byte, which does not exist in our array (the 5th element) . So, we need to subtract one element’ size from our [ebx + 4 * ecx] address.

Now, if we would like to shorten our source a bit, we may use the loop operation. What it does, is compares ECX with zero and if it is greater than zero - it jumps to a label specified.

These two codes are completely identical for processor:

manual loop :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, n</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add_loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; do something</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    dec</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    cmp</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    jg</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_loop</span></span></code>

with loop instruction :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, n</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add_loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; do something</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    loop</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_loop</span></span></code>

We’ve just saved two lines of code!

Floating-point operations

When working with floating-point data, we have seven registers, which could be used to perform operations on a floating-point arguments. We may store float data in a memory (but never in registers!) , but we may not perform operations on a float data contained in a memory. Just as we may not operate on a usual data, stored in a memory - we need to store it in registers first. Same thing here - store data on a floating-point stack and perform operations there. Then move results to the memory.

When writing a C++ functions working with floats, arguments are stored on a float stack and results are stored on a top of that stack. Yet, the other six cells of a float stack should be cleared when returning a value. Otherwise it may cause hard-to-find errors.

So, the basic operations we may run on a floats are:

  1. pushing to stack ( FLD , FLDZ , FLD1 , etc.)
  2. floating-point arithmetics ( FADD , FMUL , FDIV , FSUB , etc.)
  3. arithmetics with popping from a stack into the top stack cell ( ST0 )
  4. popping from a stack to a memory ( FST operations)

Yeah, these are a hell-yeah mix of both arithmetic operations and stack operations!

Let’s write a very short example, showing how to work with floats. Let it be a two-vector dot product function.

We shall write a function of this declaration:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdio.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extern</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "C"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot_product</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">v1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">v2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v1</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> double</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v2</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">[]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> };</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // 3*4 + 5*2 = 12 + 10 = 22</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"dot_product(v1, v2) = %0.4f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> dot_product</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This one will calculate a dot product of two n-element vectors.

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">BITS </span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    global dot_product</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dot_product</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> n dword[ebp + 8]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v1 dword[ebp + 12]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v2 dword[ebp + 16]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ecx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, n</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ebx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, v2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fldz</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; stack: 0 ( = tail)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">add_loop</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fld</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> tword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; stack: v1, tail</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fld</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> tword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">] </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; stack: v2, v1, tail</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fmulp</span><span style="color:#D20F39;--shiki-dark:#E78284"> st1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; stack: v2 * v1, tail</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    faddp</span><span style="color:#D20F39;--shiki-dark:#E78284"> st1</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; stack: v2 * v1 + tail</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add</span><span style="color:#D20F39;--shiki-dark:#E78284"> edx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">12</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    add</span><span style="color:#D20F39;--shiki-dark:#E78284"> ebx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">12</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    loop</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> add_loop</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">just_exit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    leave</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

The algorithm of a code above may be written as follows:

  1. load zero to a floating stack (ST: [0 nan nan nan nan nan nan] )
  2. in a loop load _i_th element of v1 to a floating stack (ST: [3 0 nan nan nan nan nan] )
  3. in a loop load _i_th element of v2 to a floating stack (ST: [4 3 0 nan nan nan nan] )
  4. in a loop multiply first two elements of a floating stack, write the result to ST1 and pop stack head (ST: [12 0 nan nan nan nan nan] )
  5. in a loop add first two elements of a stack, write the result to ST1 and pop stack head (ST: [12 nan nan nan nan nan nan] )
  6. in a loop add 12 bytes to our i
  7. in a loop add 12 bytes to our t

At the end of our loop, precisely, at our just_exit label, we will have floating stack with the only element on its top, the dot product of our vectors v1 and v2 . This value will be returned to our C++ program.

A few words on debugging

As you remember (if not - just look above) we added a debugger info option when compiling our programs. Now let’s use it.

Let’s have some buggy program. For example, the one which calculates a rectangular parallelepiped’s surface area and volume:

C program :

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdio.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extern</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> surface_and_volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> float</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">int</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  float</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> surface </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> volume </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  surface_and_volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">4</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 6</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#179299;--shiki-dark:#81C8BE"> &#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">surface</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  printf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"volume: %0.3f surface: %0.3f</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> surface</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

NASM program :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">BITS </span><span style="color:#FE640B;--shiki-dark:#EF9F76">32</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">section .text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    global surface_and_volume</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">surface_and_volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    enter</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a dword[ebp+8]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b dword[ebp+12]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c dword[ebp+16]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> vol_ptr dword [ebp+20] ; a*b*c</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    %</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">define</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> surf_ptr dword [ebp+24] ; a*a*2 + b*b*2 + c*c*2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, vol_ptr</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    mov</span><span style="color:#D20F39;--shiki-dark:#E78284"> ebx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, surf_ptr</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fldz</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st6</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fldz</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st5</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fldz</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fld</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; st3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fld</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; st2</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fld</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a </span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">; st1</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fldz</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; calculate volume</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fsub</span><span style="color:#D20F39;--shiki-dark:#E78284"> st0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st1</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fmul</span><span style="color:#D20F39;--shiki-dark:#E78284"> st2</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 *= b</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fmul</span><span style="color:#D20F39;--shiki-dark:#E78284"> st3</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 *= c</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fst</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> dword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">eax</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; calculate surface</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fsub</span><span style="color:#D20F39;--shiki-dark:#E78284"> st0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st1</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fmul</span><span style="color:#D20F39;--shiki-dark:#E78284"> st2</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 *= b</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st4</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st4 = a*b</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fsub</span><span style="color:#D20F39;--shiki-dark:#E78284"> st0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st1</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fmul</span><span style="color:#D20F39;--shiki-dark:#E78284"> st3</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 *= c</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st5</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st5 = a*c</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fsub</span><span style="color:#D20F39;--shiki-dark:#E78284"> st0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st2</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = b</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fmul</span><span style="color:#D20F39;--shiki-dark:#E78284"> st3</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st6</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st6 = b*c</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fsub</span><span style="color:#D20F39;--shiki-dark:#E78284"> st0</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#D20F39;--shiki-dark:#E78284">st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st4</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st5</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st6</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = a*b + a*c + b*c</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fadd</span><span style="color:#D20F39;--shiki-dark:#E78284"> st0</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> ; st0 = 2*(a*b + a*c + b*c)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">just_exit</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fst</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> dword</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [</span><span style="color:#D20F39;--shiki-dark:#E78284">ebx</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    ; free float stack</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fstp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fstp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fstp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fstp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fstp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fstp</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ret</span></span></code>

Compile it as usual and run with GDB:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -c</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3.c</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3_c.o</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> nasm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -felf32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3.asm</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3_asm.o</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> g++</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -m32</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -g</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3_asm.o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3_c.o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -o</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gdb</span><span style="color:#40A02B;--shiki-dark:#A6D189"> test3</span></span></code>

Now, when you’re in a debugger’ console, you may run debugging commands. Here are a few of them:

  • r or run will run your program, stopping at first breakpoint
  • b func_name or break func_name will set a breakpoint at the first line of func_name
  • p var or print var will show the var variable contents in decimal format. For registers its $eax and so on
  • p /x var or print /x var will show the var variable contents in hexadecimal format
  • x mem_addr will show the contents of memory at mem_addr
  • x/4 mem_addr will show four 4-byte pieces of memory at mem_addr
  • disassemble will print out the assembly code for current function
  • (from breakpoint) c or continue will run program until it hits end or breakpoint
  • (from breakpoint) ni will step one instruction
  • (from breakpoint) n or next will step over the next function (in C) ; for ASM it’s same as ni
  • (from breakpoint) s or step will step in the next function (in C) ; for ASM it’s same as ni
  • info r shows current registers’ state
  • info float shows current co-processor state
  • Ctrl+D stands for quit

Now, using GDB, try to find out what’s wrong with the program I’ve suggested!

Afterword

This is currently most of important things I’ve learnt at the university. This is pretty much for a beginner. And this information is really for those who have fun writing code or those who are made to write some excercises at university.

As for me, now ASM does not look so scary now =) But I like writing more high-level code (in C at least!) because it takes less time to do more.

ShootThem! urn:uuid:a578e1f6-21e0-5e00-a818-ed1db5a38463 2015-04-06T00:00:00Z 2015-04-06T00:00:00Z ShootThem! Artem Shubovych

A few days ago I’ve found my old game, ShootThem! sources.

Half of hour being trying to run it, and viola!

I have hosted sources with all the dependencies on GitHub .

One has no story (in-game, but has one written before the game presentation on a programming competition for students in Dnepropetrovsk). It has (almost) no colors. No code structure or architecture. No animations.

It is really plain.

Yet, it was and still it is a starting point for me 😁

Here are some of game screenshots:

Running Qt + MySQL application urn:uuid:54e88942-5034-51a1-9573-42a98df1bed0 2015-03-29T00:00:00Z 2015-03-29T00:00:00Z Running Qt + MySQL application Artem Shubovych

Yesterday I tried to run my university project made with Qt and MySQL. But all I got was strange error message, saying QMYSQL driver is not loaded whilst loaded driver list actually included that one.

Searching all over the internet up until 2AM and recompiling the whole Qt gave no result except time being wasted. Yeah, and 90% of search results were tutorials on how to recompile Qt MySQL plugin under Windows.

Yet in the morning I found solution and it was beautifully simple! I just performed one step from Deploying Qt applications , actually just copied the plugins/ directory to the dir where the application executable lives ( build-debug/ or build-release/ for my project; I hate the default build-#{ProjectName}-Desktop_5_4_1-Debug/ paths); included the sqldrivers/ directory there (just copied) and created (a bit tuned although) the qt.conf file. That file just pointed the plugins path to the custom one:

<code class="language-conf">[Paths]
Prefix=.
Plugins=./plugins
</code>

To sum everything up:

  1. create a plugins/ directory in your build directory
  2. copy Qt/5.4/Src/qtbase/plugins/platforms/ there
  3. copy Qt/5.4/gcc_64/plugins/sqldrivers/ there too
  4. create qt.conf file in build directory and fill it as mentioned above

And one more hint before the end: to debug why your Qt plugins fail use this application startup switch: QT_DEBUG_PLUGINS=1 ./app_name - this will display plugins debug information.

Tiny java code... urn:uuid:5def7a43-ea92-5abb-bb8d-60305cab04a2 2015-03-27T00:00:00Z 2015-03-27T00:00:00Z Tiny java code... Artem Shubovych

This one was super easy so I did a quick comparison of a couple of ways you can do it; the goal is to count all the alphanumeric (a-zA-Z0-9) characters in the text of a Sherlock Holmes book. There’s probably other ways do do it because there’s lots of ways to do literally anything, but the fastest one here is stripping out all non-alphanumeric characters (\W).

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//*********************************************//</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//                                             //</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//        EASY DAILY PROGRAMMING TASK #19      //</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//        ALPHANUMERIC CHARACTER COUNTING      //</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//                                             //</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">//*********************************************//</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> count1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">currentTimeMillis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    for</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> c </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toCharArray</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ((</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">c </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">matches</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"[a-zA-Z0-9]"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            count</span><span style="color:#179299;--shiki-dark:#81C8BE">++</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">currentTimeMillis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Count 1: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " Time taken: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> count2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">currentTimeMillis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> count1 </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">replaceAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">w"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">currentTimeMillis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Count 2: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count1 </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " Time taken: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> count3</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">currentTimeMillis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">replaceAll</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\\</span><span style="color:#40A02B;--shiki-dark:#A6D189">W"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    long</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> end </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">currentTimeMillis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    System</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">out</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">println</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"Count 3: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">length</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " Time taken: "</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">end </span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
<code>Countiung all alphanumeric characters in Sherlock.txt:
Count 1: 432188 Time taken: 269
Count 2: 432188 Time taken: 53
Count 3: 432188 Time taken: 22
</code>

tinyjavacode :

The new hardcore urn:uuid:c24baf78-e3ed-55b1-bea2-85f80ebc5be2 2015-03-25T00:00:00Z 2015-03-25T00:00:00Z The new hardcore Artem Shubovych

Trying some new hardcore - Assembly in Emacs 😁

Decorator pattern in Python urn:uuid:85e7925b-5a25-5f62-b49d-df00cd2b5166 2015-03-24T00:00:00Z 2015-03-24T00:00:00Z Decorator pattern in Python Artem Shubovych

Just found some interesting way of implementing Decorator design pattern in Python.

As Jason Smith said in his book ( Elemental Design Patterns ), “design patterns may be implemened in different ways in different programming languages” .

That’s said, design patterns are not some set of classes which will be implemented in a very similar way in different languages - they are just a way of doing something.

Thus, Decorator pattern is a way of wrapping some method’s or class’ behaviour. In Python it may be done with Context Managers:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> contextlib </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">import</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> contextmanager</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">@contextmanager</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> tag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">%s</span><span style="color:#40A02B;--shiki-dark:#A6D189">>"</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    yield</span></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">%s</span><span style="color:#40A02B;--shiki-dark:#A6D189">>"</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> tag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"h1"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "moo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">print</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">with</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> tag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"div"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "foo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span></code>

This code will end up wrapping print "foo" and print "moo" methods with printing some HTML tags around ‘em:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">h1</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">h1</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">foo</span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;/</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

That is interesting as it implements Decorator design pattern in a bit hard-coded way, but using language features, not OOP ones.

Compare it to the "standard" OOP implementation in Python:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># -*-coding:utf-8 -*-</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> SimpleText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic">object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    def</span><span style="color:#04A5E5;font-style:italic;--shiki-dark:#99D1DB;--shiki-dark-font-style:italic"> __init__</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">        self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    def</span><span style="color:#04A5E5;font-style:italic;--shiki-dark:#99D1DB;--shiki-dark-font-style:italic"> __str__</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> TagDecorator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">SimpleText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    def</span><span style="color:#04A5E5;font-style:italic;--shiki-dark:#99D1DB;--shiki-dark-font-style:italic"> __init__</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> tag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic">        super</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TagDecorator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#04A5E5;font-style:italic;--shiki-dark:#99D1DB;--shiki-dark-font-style:italic">__init__</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">text</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">        self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tag </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> tag</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '&#x3C;</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">{0}</span><span style="color:#40A02B;--shiki-dark:#A6D189">></span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">{1}</span><span style="color:#40A02B;--shiki-dark:#A6D189">&#x3C;/</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">{0}</span><span style="color:#40A02B;--shiki-dark:#A6D189">>'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">format</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">tag</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#8839EF;font-style:italic;--shiki-dark:#CA9EE6;--shiki-dark-font-style:italic"> super</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">TagDecorator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic"> self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE">content</span><span style="color:#7C7F93;--shiki-dark:#949CBB">())</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> SimpleText</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'moo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">print</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'SimpleText: </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">%s</span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">b </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> TagDecorator</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'moo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'h1'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#FE640B;font-style:italic;--shiki-dark:#EF9F76;--shiki-dark-font-style:italic">print</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'TagDecorator (h1): </span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">%s</span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#179299;--shiki-dark:#81C8BE"> %</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> b</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

This one looks a bit… ugly… right? And though Python does not really care of which type are a and b , we may not need all this class hierarchy.

This is the might of context managers !

How to adjust widget size in Qt urn:uuid:1a35dfa2-3367-5de7-9e1b-7cb16a942807 2015-03-24T00:00:00Z 2015-03-24T00:00:00Z How to adjust widget size in Qt Artem Shubovych

Have you ever thought on how this:

could be turned to this:

without manually setting per-pixel sizes?

It's simple as 1-2! Just take a look at the top of the UI editor and you'll find a set of buttons, dedicated to do this adjustment for you:

Yet, there is just one small tip: first you should select a containing widget, whose children will be rearranged.

Like this:

Note the selected parent widget for vertical_layout .

Modelling in Blender urn:uuid:331a154a-6d66-550c-8f82-24f9d6b9b852 2015-03-12T00:00:00Z 2015-03-12T00:00:00Z Modelling in Blender Artem Shubovych

How did I came over from that to this...

NB: this is a 3D model potentially to be used in my ShootThem! game. Inspired by the Chicken Hat from Fable:

Chicken Hat from Fable
Trying sculpting in Blender urn:uuid:97825b3a-bc8a-53a3-9d72-afef6e32828b 2015-03-04T00:00:00Z 2015-03-04T00:00:00Z Trying sculpting in Blender Artem Shubovych
Chicken body sculpt in Blender Chicken head in Blender

Have had some free time and tried sculpting in Blender 😜 With some other nice stuff 😁

creating some gun from a rough primitive model urn:uuid:ae7242b1-dc10-557e-8fc1-7cfd1796e519 2015-03-04T00:00:00Z 2015-03-04T00:00:00Z creating some gun from a rough primitive model Artem Shubovych
Textured rifle made in Blender Rifle model with few material properties and a bit of sculpting

Creating some gun from a rough primitive model with some texture and sculpting. Yet, trying to get some pretty materials on this...

reworked materials for my rifle urn:uuid:4a9c6ecd-6d96-5731-963d-0f05f0c4bf47 2015-03-04T00:00:00Z 2015-03-04T00:00:00Z reworked materials for my rifle Artem Shubovych

Reworked materials for my rifle

Having fun with Blender urn:uuid:35fa3078-8323-552d-80c1-552e6511b52a 2015-02-23T00:00:00Z 2015-02-23T00:00:00Z Having fun with Blender Artem Shubovych
Having fun texturing chicken head in Blender

Just some WIP. Having fun with Blender 😊

Installing deb package with dependencies urn:uuid:4c5a8ef6-08d2-5eab-ada0-f4d697cc626b 2015-02-19T00:00:00Z 2015-02-19T00:00:00Z Installing deb package with dependencies Artem Shubovych

Often, the command

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> sudo</span><span style="color:#40A02B;--shiki-dark:#A6D189"> dpkg</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -i</span><span style="color:#40A02B;--shiki-dark:#A6D189"> package_file.deb</span></span></code>

fails with messages like dependency not satisfied .

There are two ways to fix this:

  1. sudo dpkg -i package_file.deb &#x26;&#x26; sudo apt-get -f install
  2. sudo dpkg -i --force-depends package_file.deb

Obviously, the second one is better because it is shorter 😁

My very first model in Blender urn:uuid:f5d448af-0077-55b6-8aff-7bc9516bfc0d 2015-02-17T00:00:00Z 2015-02-17T00:00:00Z My very first model in Blender Artem Shubovych
Cup modelled in Blender Textured cup in Blender

Playing around with Blender - rendering, modifiers and some basic texturing and materials.

Rails tips urn:uuid:782376f5-e86e-53a2-a250-7894d70f7f0d 2015-02-09T00:00:00Z 2015-02-09T00:00:00Z Rails tips Artem Shubovych

Found these on HabraHabr today. Here are some tricks I found usefull.

Private methods are not actually private

Let us have class:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  private</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self.foo</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    puts</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Here, class method foo is not private:

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Foo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foo</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span></span></code>

Instance with params

Oftenly there is a need to create a class instance and set it some params (or, maybe, call some methods on it). It's done usually like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foo</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bar</span></span></code>

This can be shortened with the use of `tap` method:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">tap</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foo</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bar</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span></code>

Yet, it is more ruby-convenient and ruby-style to do it with the initialization block:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  attr_accessor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">foo</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">block</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    yield</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> block_given?</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> bar</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    puts</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "bar!"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foo</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'foo'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">bar</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">puts</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">foo</span></span></code>

Or even like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">block</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    instance_eval </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">block </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> block_given?</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">val</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#D20F39;--shiki-dark:#E78284"> nil</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    @moo </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unless</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> val</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    @moo</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> bar</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    puts</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "bar!"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  moo </span><span style="color:#40A02B;--shiki-dark:#A6D189">'moo~!'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  bar</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">puts</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> a</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">moo</span></span></code>

Code-dependent migrations

When you have your migrations using your code, for example, like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CreateDataVolumes</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActiveRecord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Migration</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> up</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">VOLUMES</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      create_table </span><span style="color:#40A02B;--shiki-dark:#A6D189">"data_</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">t</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

you then have a problem when updating your code. In our example, if you remove the constant Data::VOLUMES , you will have to either manually search for all the usages of this constant, or have a really intelliJent IDE ;)

Rather than using your existing code, stub it and copy-and-paste all migration-dependent code to the stubbing class:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> CreateDataVolumes</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActiveRecord</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Migration</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x3C;</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> AR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Base</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    VOLUMES</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> up</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    Data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">VOLUMES</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">times</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">volume</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">      # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Example with constant is rather stupid, whilst you may have some more critical code.

Abstract classes vs interfaces urn:uuid:85604023-a9f1-5c54-a04b-01a001f6147c 2015-02-03T00:00:00Z 2015-02-03T00:00:00Z Abstract classes vs interfaces Artem Shubovych

Lately I was a few times asked a question "what do we need abstract classes for?"

And today I've got one more question, which inspired me to write this.

Let us have a task to write an application, which will perform some simple arithmetic operations on numbers, represented in a different numeric systems.

For example, our program should be able to add numbers in roman , arabic and hexadecimal systems. But later we should be able to add more operations, like division , multiplication and subtraction .

This is where an abstract class comes to help us!

Rather than write an interface Number , which will define the addition operator and then implementing it for each class like RomanNumber and HexadecimalNumber we will better use an abstract class , which will be able to add decimal numbers and will declare abstract method to convert number itself to decimal system.

Take a look:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> INumber</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> INumber</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">INumber</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> other</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RomanNumber</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> INumber</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> RomanNumber</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">INumber</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> other</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // when `other` is not a RomanNumber</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // convert other to RomanNumber</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // add `other` to `this`</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> HexadecimalNumber</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> INumber</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> HexadecimalNumber</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">INumber</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> other</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // convert other to HexadecimalNumber and add...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

...and compare it to this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Number</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fromDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">Integer</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Number</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> add</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Number</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> other</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        returh </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">fromDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">this</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> other</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">toDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">());</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RomanNumber</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // convert `this` to Integer</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> RomanNumber</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fromDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // convert `n` to RomanNumber</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> HexadecimalNumber</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Number</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> Integer</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> toDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // convert `this` to Integer</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> HexadecimalNumber</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> fromDecimal</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">Integer</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic"> n</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // convert `n` to HexadecimalNumber</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

This is how we can create an abstraction: we can add or perform any other arithmetic operations regardless on which numeric system we use!

Wneh we declare an interface , we can't tell how to create an object, implementing that interface. E. g., we can not define even a default constructor.

Thus, when we need to have at least one constructor of a defined signature, we must use abstract classes .

Check it out:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> interface</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Vector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> // something like a default constructror</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Vector2d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> implements</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> IVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // THIS IS NOT A CONSTRUCTOR!</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    @Override</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Vector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

and compare it to this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> abstract</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> abstract</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> BaseVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Vector2d</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseVector</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Vector2d</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // now it DOES HAVE a default constructor super();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>
Erlang practice urn:uuid:ae69f176-0616-5f57-83ca-754fe31f7190 2015-01-28T00:00:00Z 2015-01-28T00:00:00Z

Foreword

First time I faced functional programming, I was impressed. Just a bit. That was back in 2012. The second time, I was studying real functional programming at the university. Today was the final test.

We were taught many interesting things about functional programming and lot of things about Haskell. But there were only two lectures and two practices on Erlang. And nothing was told about its distributed programming abilities.

I was a bit disappointed by this fact. So, I turned on my girlfriend's laptop, installed Erlang and created this short intro to distributed programming in Erlang.

Artem Shubovych

Foreword

First time I faced functional programming, I was impressed. Just a bit. That was back in 2012. The second time, I was studying real functional programming at the university. Today was the final test.

We were taught many interesting things about functional programming and lot of things about Haskell. But there were only two lectures and two practices on Erlang. And nothing was told about its distributed programming abilities.

I was a bit disappointed by this fact. So, I turned on my girlfriend's laptop, installed Erlang and created this short intro to distributed programming in Erlang.

Requirements

This short intro does not include Erlang tutorial and requires you to have at least two machines - either Virtual or hardware, if you wish. Even that does not really matter!

How to get out of a train?

Gordon Freeman trying to get out of a train

The first thing I gonna tell you, is really handy tip.

There are three ways to exit Erlang' shell:

  • "classic": hit Ctrl + C , then press a (Abort) and Return
  • "UNIX-way": two times hit Ctrl + C
  • "Erlang-way": simply type q(). and hit Return

You'll be happy to know 'bout last two - they are just easier!

Rock'n'Roll!

So, let's just dive into distributed programming! First thing you'll gonna need - is to know your machines' IP addresses. Then you'll gonna need to point each of them to the other one - just set each other's hostname in the /etc/hosts file _(for Windows it's C:\Windows\system32\drivers\etc\hosts )_s.

I have had two laptops I named moonode (my laptop) and foo (my girlfriend's laptop) . So, on my Ubuntu, I added this line to /etc/hosts :

<code>192.168.2.33    foonode
</code>

And in C:\Windows\system32\drivers\etc\hosts on my girlfriend's laptop I added this:

<code>192.168.2.237   moonode
</code>
hosts in Windows

Note: I was sitting at home, so laptops were connected just to my home WiFi router. And that's great news for enyone, who wants to try that at home!

Each Erlang instance was run with the corresponding shortname of machine: erl -sname moo@moonode and erl -sname foo@foonode .

Both machines should have the same cookie to communicate. That's basic Erlang security, for your great good. Cookie is just a upper-cased word, stored in a .erlang.cookie file. For Windows, that file is in the C:\Windows\ or C:\Users\username\ directory. In Linux that's in /home/username/ directory.

Wrapping-up

So, short summary on what you should have to run distributely in Erlang:

  • hostname(-s) of other node(-s) in your hosts file
  • same cookie for all your nodes in .erlang.cookie file
  • running instances with corresponding shortnames and hosts

Running stuff

To show some code, I wrote this short module:

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">test</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">-</span><span style="color:#DF8E1D;--shiki-dark:#E5C890">export</span><span style="color:#7C7F93;--shiki-dark:#949CBB">([</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> -></span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    receive</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> M </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> -></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">format</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">">> </span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">n"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> M </span><span style="color:#7C7F93;--shiki-dark:#949CBB">]),</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        finish </span><span style="color:#7C7F93;--shiki-dark:#949CBB">-></span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">            io</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">format</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"&#x3C; finish received ></span><span style="color:#7C7F93;--shiki-dark:#949CBB">~</span><span style="color:#40A02B;--shiki-dark:#A6D189">n"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            ok</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span></span></code>

Now, let's start that!

First, I registered that process with some name on the foo node:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">c</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">test1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">register</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">foo_pid, </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">spawn</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">test1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [])).</span></span></code>

And then, the only thing I needed to do - is just send messages from node moo !

<code><span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> foo_pid</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> foo@foonode </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#179299;--shiki-dark:#81C8BE"> !</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> msg</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Obey!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">.</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">flush</span><span style="color:#7C7F93;--shiki-dark:#949CBB">().</span></span></code>
moonode foonode

Much cooler than writing ping-pong programs, huh? =)

Robo created in a Cinema4d urn:uuid:4fbd03f5-5814-5279-a97e-db6c73f64581 2015-01-27T00:00:00Z 2015-01-27T00:00:00Z Robo created in a Cinema4d Artem Shubovych

This is a 3D model of a robot (called him Robo) which I made in Cinema4D some two and a half years ago.

Robot model
Deploying Rails project to Heroku urn:uuid:cec3c7f3-0819-5db6-9365-096353e5d821 2015-01-11T00:00:00Z 2015-01-11T00:00:00Z Deploying Rails project to Heroku Artem Shubovych

First of all, set up the Heroku Toolbelt . It is required for all the communications with the server.

The first step of communication with the Heroku servers is logging in. Just run heroku login` and provide your credentials when asked.

<p>Then, you need to create your application or go to the folder where it is located and tune it a bit. Tuning is divided into the following steps:</p> <ul> <li>tuning the <code>Gemfile</code> to include the required gems</li> <li>fixing the <code>database.yml</code> configurations</li> <li>setting the server to handle static assets correctly</li> </ul> <p>But let's create out application on the Heroku servers first: <code>heroku create [app_name]</code>. If application name is not provided directly - it will be generated automatically.</p> <p>Now, our application needs two gems to be included for the <code>production</code> gems' group:</p> <pre class="shiki shiki-themes catppuccin-latte catppuccin-frappe" style="background-color:#eff1f5;--shiki-dark-bg:#303446;color:#4c4f69;--shiki-dark:#c6d0f5" tabindex="0"><code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">group </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284">production</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span> <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gem </span><span style="color:#40A02B;--shiki-dark:#A6D189">'pg'</span></span> <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gem </span><span style="color:#40A02B;--shiki-dark:#A6D189">'rails_12factor'</span></span> <span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> gem </span><span style="color:#40A02B;--shiki-dark:#A6D189">'puma'</span></span> <span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code></pre> <p>The third gem is used as a webserver instead of WebRick, which is default (puma is much, much faster!). The second one is required by Heroku. And the first one is used for PostgreSQL connectivity. If you do not wish to use database - skip it and a few next paragraphs.</p> <p>Then, let's add the database support for our application. It's done simply, running</p> <pre class="shiki shiki-themes catppuccin-latte catppuccin-frappe" style="background-color:#eff1f5;--shiki-dark-bg:#303446;color:#4c4f69;--shiki-dark:#c6d0f5" tabindex="0"><code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">heroku</span><span style="color:#40A02B;--shiki-dark:#A6D189"> addons:add</span><span style="color:#40A02B;--shiki-dark:#A6D189"> heroku-postgresql:hobby-dev</span></span></code></pre> <p><strong>Note:</strong> Heroku does not support <code>sqlite</code> since some times. This means you are forced to use either PostgreSQL or no database at all (yes, it's possible! Yet, it works for simple or static web applications only). You may want to change this if you would pay for your account. But this tutorial covers only free side of the Heroku deployment.</p> <p>Now, there are two ways to set database connection options in Rails:</p> <ol> <li>set them directly at <code>config/database.yml</code> file</li> <li>set the environment variable <code>DATABASE_URL</code></li> </ol> <p>We will cover both cases. For the first one, you will need this section within your <code>database.yml</code> file:</p> <pre class="shiki shiki-themes catppuccin-latte catppuccin-frappe" style="background-color:#eff1f5;--shiki-dark-bg:#303446;color:#4c4f69;--shiki-dark:#c6d0f5" tabindex="0"><code><span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE">production</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span></span> <span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> adapter</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> postgresql</span></span> <span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> encoding</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> unicode</span></span> <span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> pool</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 5</span></span> <span class="line"><span style="color:#1E66F5;--shiki-dark:#8CAAEE"> url</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> URL_GOES_HERE</span></span></code></pre> <p>I will show how to get the <code>&#x3C;URL_GOES_HERE></code> value in a second. Just keep in mind to replace it with the correct value.</p> <p>The second option, the environment variable, is set via the Heroku Toolbelt (did I tell you, it is used for almost every deploy operation you will perform?).</p> <p>First you take the database URL from Heroku server:</p> <pre class="shiki shiki-themes catppuccin-latte catppuccin-frappe" style="background-color:#eff1f5;--shiki-dark-bg:#303446;color:#4c4f69;--shiki-dark:#c6d0f5" tabindex="0"><code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">heroku</span><span style="color:#40A02B;--shiki-dark:#A6D189"> config</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> grep</span><span style="color:#40A02B;--shiki-dark:#A6D189"> HEROKU_POSTGRESQL</span></span></code></pre> <p>Then, you copy the value you got (it starts with <code>postgres://</code>) and run the following:</p> <pre class="shiki shiki-themes catppuccin-latte catppuccin-frappe" style="background-color:#eff1f5;--shiki-dark-bg:#303446;color:#4c4f69;--shiki-dark:#c6d0f5" tabindex="0"><code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">heroku</span><span style="color:#40A02B;--shiki-dark:#A6D189"> config:set</span><span style="color:#40A02B;--shiki-dark:#A6D189"> DATABASE_URL=URL_GOES_HERE</span></span></code></pre> <p>Now let's set our application to serve static assets. It is handy, because it is the easiest way to send images, stylesheets and javascripts to clients. Go to the <code>config/environments/production.rb</code> and change both <code>config.serve_static_assets</code> and <code>config.assets.compile</code> to <code>true</code>.</p> <p><strong>But beware:</strong> if your <code>app/assets</code> files directory contains files of other extensions than Rails' <strong>Sprockets</strong> understands - Rails (and Heroku, particularly) will try to precompile them. And that may cause many troubles. You are recommended either to "teach" Sprockets to skip or precompile those files, <strong>or</strong> you should exclude them from project before deploying to Heroku.</p> <p>And the last two steps separate us from our goal: first, you should push your project to Heroku' Git repository, it created for you with the application (You do not use Git yet?! How dare you?!..).</p> <p>Now, if you use database, run migrations with <code>heroku run rake db:migrate</code>.</p> <p>And, finally, see your application running in the browser: <code>heroku open</code>.</p> <p><strong>Note:</strong> if you are using some assets from the outer web (GoogleFonts, for example) and are seeing your website through the <code>https</code> protocol, you should replace all those assets' URL protocols with <code>https</code> too.</p>
Connecting Lenovo P780 to ADB on Ubuntu urn:uuid:ff4e5032-358a-56f3-a2c3-e8f56a50fe97 2015-01-11T00:00:00Z 2015-01-11T00:00:00Z Connecting Lenovo P780 to ADB on Ubuntu Artem Shubovych

Ohhh... Today I've faced one great trouble: recently I reinstalled my Ubuntu, so I lost all my configurations. And when I tried to connect my Lenovo P780 to debug my Android application, I saw horrible error:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> adb</span><span style="color:#40A02B;--shiki-dark:#A6D189"> devices</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> daemon not running. starting it now on port 5037 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> daemon started successfully </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#40A02B;--shiki-dark:#A6D189"> of</span><span style="color:#40A02B;--shiki-dark:#A6D189"> devices</span><span style="color:#40A02B;--shiki-dark:#A6D189"> attached</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">????????????</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    no permissions</span></span></code>

Hey! Where have my smartphone gone?!

Fooling around in the internet, I found two simple steps to fix this:

  1. find the VendorID and ProductID for your device running lsusb two times (just find the difference line):
  2. when your device is disconnected
  3. when your device is connected

This will give you two outputs:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # disconnected device</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> lsusb</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 002:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 8087:0024</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Intel</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Corp.</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Integrated</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Rate</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Matching</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 001</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 004:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 064e:d213</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Suyin</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Corp.</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 001</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 002:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 8087:0024</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Intel</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Corp.</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Integrated</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Rate</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Matching</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 001</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 004</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0003</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 003</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # connected device (via USB)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> lsusb</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 002:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 8087:0024</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Intel</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Corp.</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Integrated</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Rate</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Matching</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 001</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 004:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 064e:d213</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Suyin</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Corp.</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 001</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 002:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 8087:0024</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Intel</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Corp.</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Integrated</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Rate</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Matching</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 001</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 004</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0003</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 003</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 006:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 0bb4:0c03</span><span style="color:#40A02B;--shiki-dark:#A6D189"> HTC</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (High </span><span style="color:#40A02B;--shiki-dark:#A6D189">Tech</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Computer</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Corp.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">Bus</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 003</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Device</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 001:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ID</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 1d6b:0002</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Linux</span><span style="color:#40A02B;--shiki-dark:#A6D189"> Foundation</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2.0</span><span style="color:#40A02B;--shiki-dark:#A6D189"> root</span><span style="color:#40A02B;--shiki-dark:#A6D189"> hub</span></span></code>

Note the row, which is present in the second output block and is absent in the first one:

<code>Bus 003 Device 006: ID 0bb4:0c03 HTC (High Tech Computer Corp.)
</code>

For some reason, my phone is recognized as a HTC, but that does not bother me so much. We will need only two parts of that row:

<code>0bb4:0c03
</code>

The 0bb4 is a VendorID and the 0c03 is the ProductID for my phone.

  1. Add the phone attributes to the system.

Sudo-edit the file /lib/udev/rules.d/69-libmtp.rules and point it to your device. Add a line like this (without any newlines):

<code>ATTR{idVendor}=="0bb4", ATTR{idProduct}=="0c03", SYMLINK+="libmtp-%k", MODE="0666", GROUP="audio", ENV{ID_MTP_DEVICE}="1", ENV{ID_MEDIA_PLAYER}="1"
</code>

That should enable your system to see the device later.

  1. Enable write permissions for your device. Sudo-edit the file /etc/udev/rules.d/51-android.rules (you may need to create it) and add one line there:
<code>SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", ATTRS{idProduct} =="0c03", MODE="0666", GROUP="plugdev"
</code>
  1. Check the phone is recognized by adb

Just restart ADB server and check its device list:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> adb</span><span style="color:#40A02B;--shiki-dark:#A6D189"> kill-server</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> adb</span><span style="color:#40A02B;--shiki-dark:#A6D189"> devices</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> daemon not running. starting it now on port 5037 </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> daemon started successfully </span><span style="color:#179299;--shiki-dark:#81C8BE">*</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">List</span><span style="color:#40A02B;--shiki-dark:#A6D189"> of</span><span style="color:#40A02B;--shiki-dark:#A6D189"> devices</span><span style="color:#40A02B;--shiki-dark:#A6D189"> attached</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">0123456789ABCDEF</span><span style="color:#40A02B;--shiki-dark:#A6D189">    device</span></span></code>
Microsoft' error messages cipher urn:uuid:b2323d28-ebad-5fd0-9cbb-d7f9fe03a55a 2015-01-09T00:00:00Z 2015-01-09T00:00:00Z

I have a T-SQL trigger creation script, which runs OK:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">CREATE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> TRIGGER</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> data_modified</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ON</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Northwind.dbo.Customers </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">FOR</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> INSERT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">UPDATE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DELETE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">AS</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">declare</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @@ROWCOUNT;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">IF</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">BEGIN</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'no rows were affected'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inserted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deleted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'updated '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'inserted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'deleted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Yet, when I run some INSERT query, I got an error saying:

<code>Msg 245, Level 16, State 1, Procedure data_modified, Line 21
Conversion failed when converting the varchar value 'inserted ' to data type int.
</code>

Mysterious, isn't it? Let's dig in, shall we?

Artem Shubovych

I have a T-SQL trigger creation script, which runs OK:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">CREATE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> TRIGGER</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> data_modified</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ON</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Northwind.dbo.Customers </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">FOR</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> INSERT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">UPDATE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DELETE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">AS</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">declare</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @@ROWCOUNT;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">IF</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">BEGIN</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'no rows were affected'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inserted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deleted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'updated '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'inserted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'deleted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Yet, when I run some INSERT query, I got an error saying:

<code>Msg 245, Level 16, State 1, Procedure data_modified, Line 21
Conversion failed when converting the varchar value 'inserted ' to data type int.
</code>

Mysterious, isn't it? Let's dig in, shall we?

Let's look onto the source of that trigger, at line 18:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">USE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [Northwind]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">GO</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">/****** Object:  Trigger [dbo].[data_modified]    Script Date: 09.01.2015 18:18:14 ******/</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">SET</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ANSI_NULLS</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ON</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">GO</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">SET</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> QUOTED_IDENTIFIER</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ON</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">GO</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    ALTER</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> TRIGGER</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [dbo].[data_modified] </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">ON</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [Northwind].[dbo].[Customers] </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">FOR</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> INSERT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">UPDATE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DELETE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    AS</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    declare</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @@ROWCOUNT;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    IF</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    BEGIN</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'no rows were affected'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inserted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deleted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'updated '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'inserted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'deleted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span></code>

Here's the error:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inserted)</span></span></code>

But wait, that can't be true!

The problem is a bit deeper, with the @rows variable:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'updated '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span></code>

while being declared as:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">declare</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span></code>

It can not be printed right away, so it needs to be cast:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">CREATE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> TRIGGER</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> data_modified</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> ON</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Northwind.dbo.Customers </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">FOR</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> INSERT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">UPDATE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DELETE</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">AS</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">declare</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">declare</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows_s </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> varchar</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">10</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @@ROWCOUNT;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">set</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows_s </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> cast</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(@rows </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">as</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> varchar</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">IF</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">BEGIN</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'no rows were affected'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> inserted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> exists</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">select</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> from</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> deleted)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'updated '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows_s </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'inserted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows_s </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">else</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">begin</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    print</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'deleted '</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @rows_s </span><span style="color:#179299;--shiki-dark:#81C8BE">+</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ' rows'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Try to guess where's your mistake, using that error message! 😉

Setting up Rails webserver urn:uuid:32eea850-c613-535a-bb13-97b989273d90 2014-12-18T00:00:00Z 2014-12-18T00:00:00Z Setting up Rails webserver Artem Shubovych

Foreword

This tutorial I wrote when was quitting my previous job, almost one year ago. But it's still handy!

Abstract Rails application setup

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> git</span><span style="color:#40A02B;--shiki-dark:#A6D189"> clone</span><span style="color:#40A02B;--shiki-dark:#A6D189"> .../project_name.git</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> cd</span><span style="color:#40A02B;--shiki-dark:#A6D189"> project_name</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [sudo] bundle install</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> cat</span><span style="color:#40A02B;--shiki-dark:#A6D189"> config/database.yml</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # create database and/or change config/database.yml settings</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> rake</span><span style="color:#40A02B;--shiki-dark:#A6D189"> db:migrate</span><span style="color:#40A02B;--shiki-dark:#A6D189"> RAILS_ENV=production</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> rake</span><span style="color:#40A02B;--shiki-dark:#A6D189"> db:seed</span><span style="color:#40A02B;--shiki-dark:#A6D189"> RAILS_ENV=production</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # don't worry if one fails</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"> # start the server of your choice</span></span></code>

Puma webserver

Application-wide settings

First you need to set up Puma for your specific project. For this purpose, add this line to the Gemfile :

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gem </span><span style="color:#40A02B;--shiki-dark:#A6D189">'puma'</span></span></code>

Then, run [sudo] bundle install .

When you are done, you should be able to create a Puma config file at $PROJECT_DIR/config/puma.rb :

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> home_dir</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">    '/home/user/$PROJECT_DIR/'</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    File</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">home_dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">directory home_dir</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">environment </span><span style="color:#40A02B;--shiki-dark:#A6D189">'development'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">daemonize</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">pidfile </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'tmp/pids/puma.pid'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">state_path </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'tmp/pids/puma.state'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">stdout_redirect </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'log/puma.log'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'log/error.puma.log'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">threads </span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 1</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">bind </span><span style="color:#40A02B;--shiki-dark:#A6D189">'tcp://0.0.0.0:5100'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">activate_control_app</span></span></code>

More details here: https://github.com/puma/puma/blob/master/examples/config.rb

Now, add project root path to the /etc/puma.conf file, e. g.:

<code>/home/user/project_name
</code>

Start Puma at boot

There is a specific utility, called Jungle . It manages your applications' instances at startup.

Ububtu-based systems

First of all, create /etc/init/puma.conf file and fill it with this:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># /etc/init/puma.conf - Puma config</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># This example config should work with Ubuntu 12.04+.  It</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># allows you to manage multiple Puma instances with</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Upstart, Ubuntu's native service management tool.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># See workers.conf for how to manage all Puma instances at once.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Save this config as /etc/init/puma.conf then manage puma with:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#   sudo start puma app=PATH_TO_APP</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#   sudo stop puma app=PATH_TO_APP</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#   sudo status puma app=PATH_TO_APP</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># or use the service command:</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#   sudo service puma {start,stop,restart,status}</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">description</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Puma Background Worker"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># no "start on", we don't want to automatically start</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#40A02B;--shiki-dark:#A6D189"> on</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (stopping </span><span style="color:#40A02B;--shiki-dark:#A6D189">puma-manager</span><span style="color:#40A02B;--shiki-dark:#A6D189"> or</span><span style="color:#40A02B;--shiki-dark:#A6D189"> runlevel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [06])</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># change apps to match your deployment user if you want to use this as a less privileged user (recommended!)</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setuid</span><span style="color:#40A02B;--shiki-dark:#A6D189"> apps</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">setgid</span><span style="color:#40A02B;--shiki-dark:#A6D189"> apps</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">respawn</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">respawn</span><span style="color:#40A02B;--shiki-dark:#A6D189"> limit</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 3</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 30</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">instance</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> ${app}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">script</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># this script runs in /bin/sh by default</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># respawn as bash so we can source in rbenv/rvm</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># quoted heredoc to tell /bin/sh not to interpret</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># variables</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">exec</span><span style="color:#40A02B;--shiki-dark:#A6D189"> /bin/bash</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> &#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;&#x26;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">lt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">'EOT'</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  # set HOME to the setuid user's home, there doesn't seem to be a better, portable way</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  export</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> HOME</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">$(</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">eval</span><span style="color:#40A02B;--shiki-dark:#A6D189"> echo ~</span><span style="color:#7C7F93;--shiki-dark:#949CBB">$(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">id</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -un</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">  cd</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $app</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -d</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$HOME</span><span style="color:#40A02B;--shiki-dark:#A6D189">/.rbenv/bin"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ];</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    export</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> PATH</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$HOME</span><span style="color:#40A02B;--shiki-dark:#A6D189">/.rbenv/bin:</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$PATH</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  elif</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  /etc/profile.d/rvm.sh </span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">    source</span><span style="color:#40A02B;--shiki-dark:#A6D189"> /etc/profile.d/rvm.sh</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  elif</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> /usr/local/rvm/scripts/rvm </span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">    source</span><span style="color:#40A02B;--shiki-dark:#A6D189"> /etc/profile.d/rvm.sh</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  elif</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -f</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$HOME</span><span style="color:#40A02B;--shiki-dark:#A6D189">/.rvm/scripts/rvm"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ];</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">    source</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$HOME</span><span style="color:#40A02B;--shiki-dark:#A6D189">/.rvm/scripts/rvm"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  elif</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> /usr/local/share/chruby/chruby.sh </span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">    source</span><span style="color:#40A02B;--shiki-dark:#A6D189"> /usr/local/share/chruby/chruby.sh</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#179299;--shiki-dark:#81C8BE"> -f</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> /usr/local/share/chruby/auto.sh </span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> then</span></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">      source</span><span style="color:#40A02B;--shiki-dark:#A6D189"> /usr/local/share/chruby/auto.sh</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    fi</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # if you aren't using auto, set your version here</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # chruby 2.0.0</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  fi</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  logger</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -t</span><span style="color:#40A02B;--shiki-dark:#A6D189"> puma</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Starting server: </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$app</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">  exec</span><span style="color:#40A02B;--shiki-dark:#A6D189"> bundle</span><span style="color:#40A02B;--shiki-dark:#A6D189"> exec</span><span style="color:#40A02B;--shiki-dark:#A6D189"> puma</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -C</span><span style="color:#40A02B;--shiki-dark:#A6D189"> config/puma.rb</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">EOT</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> script</span></span></code>

Now, create /etc/init/puma-manager.conf and fill it with this:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># /etc/init/puma-manager.conf - manage a set of Pumas</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># This example config should work with Ubuntu 12.04+.  It</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># allows you to manage multiple Puma instances with</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Upstart, Ubuntu's native service management tool.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># See puma.conf for how to manage a single Puma instance.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Use "stop puma-manager" to stop all Puma instances.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Use "start puma-manager" to start all instances.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Use "restart puma-manager" to restart all instances.</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Crazy, right?</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">#</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">description</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Manages the set of puma processes"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># This starts upon bootup and stops on shutdown</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">start</span><span style="color:#40A02B;--shiki-dark:#A6D189"> on</span><span style="color:#40A02B;--shiki-dark:#A6D189"> runlevel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [2345]</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">stop</span><span style="color:#40A02B;--shiki-dark:#A6D189"> on</span><span style="color:#40A02B;--shiki-dark:#A6D189"> runlevel</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> [06]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Set this to the number of Puma processes you want</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># to run on this machine</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">env</span><span style="color:#40A02B;--shiki-dark:#A6D189"> PUMA_CONF="/etc/puma.conf"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pre-start</span><span style="color:#40A02B;--shiki-dark:#A6D189"> script</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  for</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">in</span><span style="color:#179299;--shiki-dark:#81C8BE"> `</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">cat</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $PUMA_CONF</span><span style="color:#179299;--shiki-dark:#81C8BE">`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    app</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#179299;--shiki-dark:#81C8BE">`</span><span style="color:#D20F39;font-style:italic;--shiki-dark:#E78284;--shiki-dark-font-style:italic">echo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $i</span><span style="color:#179299;--shiki-dark:#81C8BE"> |</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> cut</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -d , -f </span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#179299;--shiki-dark:#81C8BE">`</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    logger</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -t</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "puma-manager"</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Starting </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$app</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    start</span><span style="color:#40A02B;--shiki-dark:#A6D189"> puma</span><span style="color:#40A02B;--shiki-dark:#A6D189"> app=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$app</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  done</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> script</span></span></code>

And create a blank /etc/puma.conf file. This will be filled for each application separately.

Caveat:

You need to customise /etc/init/puma.conf to:

  • Set the right user your app should be running on unless you want root to execute it!
    • Look for setuid apps and setgid apps , uncomment those lines and replace apps to whatever your deployment user is.
    • Replace apps on the paths (or set the right paths to your user's home) everywhere else.
  • Uncomment the source lines for rbenv or rvm support unless you use a system wide installation of Ruby.

Now, start Jungle like this: sudo start puma-manager . And all your applications should be available when you reboot the machine.

More details at https://github.com/puma/puma/tree/master/tools/jungle/

Debian-based systems

PENDING

Starting up and shutting down

To start up the application is easy enough. Just navigate yourself to project directory and run the following: puma -C config/puma.rb .

If you want to shut down one, run this command in the project directory: [sudo] pumactl -S tmp/pids/puma.state halt .

Speeding up with Ruby native extensions urn:uuid:4ecc3692-5713-556a-97a8-c20e9a6b7dc7 2014-11-15T00:00:00Z 2014-11-15T00:00:00Z

Foreword

At my job, our current project has many bottle-necks, where Ruby really sucks on its performance. We were thinking on how to optimize them, and finally come to usage of Ruby Native API.

Our project uses Redis and MySQL hardly, so much of statistic data is stored in Redis. For speeding up. But one fine day made us use a reduce on a set of statistic data from Redis. And that’s where we got stuck on Ruby’ performance. Our server timed out in a minute of waiting for that reduce to complete.

Artem Shubovych

Foreword

At my job, our current project has many bottle-necks, where Ruby really sucks on its performance. We were thinking on how to optimize them, and finally come to usage of Ruby Native API.

Our project uses Redis and MySQL hardly, so much of statistic data is stored in Redis. For speeding up. But one fine day made us use a reduce on a set of statistic data from Redis. And that’s where we got stuck on Ruby’ performance. Our server timed out in a minute of waiting for that reduce to complete.

The trouble was in a loop like this:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">json_data </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> JSON</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">pase</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">json_file</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">keys </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $redis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">keys</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "*:hash_pattern:date:*"</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">count</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> total_count </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">hash_key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    elements </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $redis</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">hgetall</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> hash_key</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    elements</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        i_value </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_i</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        count </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i_value </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> key =~ </span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#40A02B;--shiki-dark:#A6D189">some:regex</span><span style="color:#7C7F93;--shiki-dark:#949CBB">/</span><span style="color:#179299;--shiki-dark:#81C8BE"> and</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> json_data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">has_key?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> key</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        total_count </span><span style="color:#179299;--shiki-dark:#81C8BE">+=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> i_value</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

My first attempt was implemented on a D language. But when I tried to use the compiled code library with Ruby, I failed. That’s why I thought I feel more comfortable with C/C++ than with D . And wrote the same code on C/C++. I took three third-party libraries:

  • RE2 for regular expressions
  • hiredis for Redis operations
  • rapidjson for JSON parsing

But when I compiled and ran what I’ve done, I could not believe my eyes - the process worked for 59 seconds ! That was more than ten times slower than Ruby version!

So, I started optimizing for speed.

First of all, I dropped regular expressions as they were simply replaced by substring check and substring extraction (as the first part of a string in a regular expression had a fixed length). That did the trick, lowering the execution time to 25 seconds . Yet, it was too much.

The last step I took, I removed hiredis and replaced it with a set of five custom functions, performing only those operations, which we needed via sockets. First, that failed with a really, REALLY long segfault. Yet, when I replaced the host string from “localhost” to “127.0.0.1” , my tiny extension arose and did its job in 4.8 seconds .

That was great! Yet, it is not the best time I can get, let’s take a look on what was done and in which manner.

Creating native extensions for Ruby

Creating a native extension will need you to have compiled shared object file. Shared object is a library for POSIX OSes. There are two kinds of library formats for Linux and others:

  • shared libraries ( *.so files) - could be placed anywhere and used in a runtime by a few applications
  • static libraries ( *.a files) - are bundled to a compile target (library, executable...) and are used in that environment

For that purpose you’d better use C/C++ Ruby API . Yes, you could use other-language-compiled shared libraries, but through an interface called FFI , which I did not manage to work for me. Thus, this article covers only the C/C++ way.

To make your extension available in Ruby, you will need to define some of these:

  • method for existing classes and modules
  • new class or module

All of them are not hard to implement. We will make our own module and define its method.

First, create a directory names as your extension will be named. Let’s say, my_ext . Create two files there - my_ext.cpp and extconf.rb . First file will define an extension shared library, whilst the second one will create Makefile for us.

Our extension will have a very simple source file with just one non-standard include and two functions defined:

<code><span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "ruby.h"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;string.h></span></span>
<span class="line"><span style="color:#DF8E1D;--shiki-dark:#E5C890">#include</span><span style="color:#40A02B;--shiki-dark:#A6D189"> &#x3C;stdlib.h></span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">VALUE </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">moo_method</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">VALUE </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VALUE </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_age</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> VALUE </span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">_self</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    char</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> StringValueCStr</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    unsigned</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> age </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> num2uint</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">_age</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    char</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#179299;--shiki-dark:#81C8BE">*</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> malloc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#FE640B;--shiki-dark:#EF9F76">255</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#179299;--shiki-dark:#81C8BE"> sizeof</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">char</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    sprintf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello, my name is %s and I am %d years old!</span><span style="color:#EA76CB;--shiki-dark:#F4B8E4">\n</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> age</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> rb_str_new2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">extern</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "C"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">void</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Init_my_ext</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  VALUE MyModule </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> rb_define_module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"MyModule"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">  rb_define_module_function</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">MyModule</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "moo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> reinterpret_cast</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> 2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Now let’s look at this source. There is only one exported function, Init_my_ext . That’s correct, because all our extension needs to do is to define something. And that is done in that method. The function Init_my_ext should have such name format: Init_$extension_name$ . That’s how Ruby finds out what to call first.

Now, there are many of those VALUE type instances. That is internal type of Ruby Native API. That is the variant type, holding Ruby’ value. And whilst Ruby is not strongly typed language, that type could contain anything - from nil to string and even object . There are a few really useful functions defined in ruby.h to help you checking variables for types and converting them to C++ types.

Then we define a module named MyModule and stored its reference in the MyModule variable. Then we can do what we want with that module - define classes, variables and methods. Let’s see how we defined a method. Function rb_define_module_function contains four arguments:

  • reference to a module
  • method name
  • pointer to a C function, representing method internals - note the reinterpret_cast
  • argument count - when this number is less than zero, than method will receive three arguments - int argc , VALUE* argv and VALUE self , representing variable amount of arguments; if this number is greater than zero - it defines the amount of required method arguments

Now, lets create a extconf.rb file, which will create Makefile for final library compilation:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">require</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'mkmf'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">extension_name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'my_ext'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get_dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">    File</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">expand_path</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">File</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">File</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dirname</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__FILE__</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">LIBDIR</span><span style="color:#179299;--shiki-dark:#81C8BE">     =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RbConfig</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CONFIG</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'libdir'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">INCLUDEDIR</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> RbConfig</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">CONFIG</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'includedir'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">HEADER_DIRS</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> INCLUDEDIR</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># setup constant that is equal to that of the file path that holds that static libraries that will need to be compiled against</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">LIB_DIRS</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> LIBDIR</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">libs </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> []</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># The destination</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dir_config</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">extension_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> HEADER_DIRS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> LIB_DIRS</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">libs</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lib</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    $LOCAL_LIBS </span><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;&#x3C;</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">lib</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Additional compiler / linker flags</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># $CFLAGS &#x3C;&#x3C; " -fPIC "</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># $LDFLAGS &#x3C;&#x3C; " -lpthread "</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># Do the work</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">create_makefile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">extension_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

That’s it, it defines parameters for our future Makefile . Note the get_dir(name) method - I’ve defined it for you to simplify adding library sub-directories to the LIBDIR and INCLUDEDIR arrays, just like this:

<code><span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">LIB_DIRS</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> LIBDIR</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get_dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'hiredis'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span></code>

Also, note the -fPIC option - it is needed for most libraries to compile under different architectures. So, you may need to add them to your third-party libraries’ Makefiles to resolve corresponding compiler errors when building the extension.

When you are done, let’s generate Makefile:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">ruby extconf</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">rb</span></span></code>

Then, you should be able to build your shared object with

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> make</span></span></code>

Using our extension is simple when playing around locally - you just add it to your irb or ruby command-line arguments like this:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> irb</span><span style="color:#40A02B;--shiki-dark:#A6D189"> -r</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ./my_ext.so</span></span></code>

And then just using the modules you’ve defined. But in most situations, that is impossible, as, for example, you are running a Rails application on a production server. So, you will probably want a RubyGem for that purpose.

Wrapping extension in a Gem

Building a Ruby Gem containing native extension is a little different than building usual gems. You here have two options:

  • bundle a pre-built library with a gem
  • provide a sources to perform build on a target machine

First way is for dummies. That’s it, you will probably want your code ran on different platforms than your own machine. So, you will not want your gem to fail with a segfault like this architecture differs from what the library was built on . Thus, we will concentrate on a second way.

First, we will need a correct directory structure:

<code>.
├── ext
│   └── my_gemname
│       ├── extconf.rb
│       └── my_ext.cpp
├── lib
│   └── my_gemname.rb
└── my_gemname.gemspec
</code>

File lib/my_gemname.rb will contain only the extension initialization call:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">require</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'my_gemname/my_ext'</span></span></code>

Whilst the main difference hides in gemspec file:

<code><span class="line"><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Gem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Specification</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">name</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'my_gemname'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">version</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '0.1'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">description</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Some cool description here'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">summary</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Short description'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">email</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '[email protected]'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">homepage</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ''</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">author</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Author Name'</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">files</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'lib/**/*.rb'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ext/**/*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">platform</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Gem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Platform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">RUBY</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">require_paths</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'lib'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ext'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">extensions</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ext/my_gemname/extconf.rb'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Here four lines make the magick:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">files</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'lib/**/*.rb'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> +</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ext/**/*'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">platform</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Gem</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Platform</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">RUBY</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">require_paths</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> [</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'lib'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'ext'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> ]</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  spec</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">extensions</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Dir</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'ext/my_gemname/extconf.rb'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span></span></code>

They set, respectively:

  • directories of the extension with all the files and sub-directories, needed to compile it
  • universal target platform
  • extension required path
  • path to the extension’ extconf file

Now you can build your gem with

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gem</span><span style="color:#40A02B;--shiki-dark:#A6D189"> build</span><span style="color:#40A02B;--shiki-dark:#A6D189"> my_gemname.gemspec</span></span></code>

Using the gemfile may require you never to push it to RubyGems repository. For example, when your gem is a very specific for the project you are working on, or it may conflict with your job contract. But you can’t simply specify the path attribute for your gem in the Gemfile - it just does not work!

Way to solve this lays beyound using custom repository. My solution was to create a directory under lib/ sub-directory of our project:

<code>repository
└── gems
    └── my_gemname-0.1.gem
</code>

Then, go to the repository directory (that’s important NOT to go to the gems subdir) and run this magic command:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">$</span><span style="color:#40A02B;--shiki-dark:#A6D189"> gem</span><span style="color:#40A02B;--shiki-dark:#A6D189"> generate_index</span></span></code>

This will make your repository directory look like this:

<code>repository
├── gems
│   └── my_gemname-0.1.gem
├── latest_specs.4.8
├── latest_specs.4.8.gz
├── prerelease_specs.4.8
├── prerelease_specs.4.8.gz
├── quick
│   └── Marshal.4.8
│       └── my_gemname-0.1.gemspec.rz
├── specs.4.8
└── specs.4.8.gz
</code>

This directory now could be used as a RubyGems repository. Just like the rubygems.org ! Just point your Gemfile to this directory:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">source </span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">File</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'file://'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> File</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">dirname</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__FILE__</span><span style="color:#7C7F93;--shiki-dark:#949CBB">),</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'lib'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'repository'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span></code>

And an important note : keep your Gemfile and Gemfile.lock up-to date - use only = latest.version in the Gemfile when running with your native extension gem!

Чоткій блог. Часть третя urn:uuid:30de6c15-dd4d-55a1-a052-54dfc0d544e1 2014-07-28T00:00:00Z 2014-07-28T00:00:00Z

Прєдупрєждєніє

Будь готов! В цій главі ми полностью переробим блог! Він не буде працювати (як раньше) аж до кінця домашнього заданія; код буде магічним; придеться пару раз удалять весь код з деяких файлів! Але в сухом остаткє, потом має стати ну дуже прикольно розробляти його дальше.

Artem Shubovych

Прєдупрєждєніє

Будь готов! В цій главі ми полностью переробим блог! Він не буде працювати (як раньше) аж до кінця домашнього заданія; код буде магічним; придеться пару раз удалять весь код з деяких файлів! Але в сухом остаткє, потом має стати ну дуже прикольно розробляти його дальше.

RIP, блог!

От коли-небудь ти точно міг замітить, шо на сайтах мало ссилок з адрєсами віда some_file.php?... . А більше ссилок віда /moo/foo . Так от, не зря ми чуть раньше вспоминали про MVC . У нас ще осталось цілих дві букви для расшифровки - Controller і View .

Раньше у нас один контроллєр отвічав чотко за одну странічку, за один php-файл. І ти помниш, як ми круто зробили з моделями, шоб можна було щитай пустий клас (ну і, канєшна, соотвєтствующу табличку в базє даних) создать - і модель у нас работала. От давай тепер зробим так, шоб і з кантроллєрами у нас було шось похоже - один клас отвічає за кучу разних странічок!

В всяких там Ruby On Rails, ASP.NET MVC, Django і прочіх модних мейнстрімових фреймворках штука “контроллєр” оброблює багато всяких странічок, об’єдіньонних похожой функциональностью. Каждий публічний метод контроллєра називається action і обрабатує виключно одну странічку. Так, напрімєр, якшо у нас є контроллєр “Пости”, він обрабатує всьо шо зв’язано тільки з постами:

  • редактірованіє
  • удалєніє
  • созданіє
  • просмотр
  • просмотр списка всіх постів

По суті, весь наш блог - це одна програма. В народі - application . Так давай зробим клас, який буде “запускать” наш сайт! Назвем цей клас Application і положим ми його рядом з index.php . В цьому класі нада зробить якийсь мєтод, який буде задавать настройки нашому сайту ( конкрєтно нашому сайту ) і мєтод, який буде собсно запускать наш сайт з цими настройками.

Якшо ти вніматєльно ізучав ООП, то поймеш, шо по феншую треба всякі пєрємєнні, які стосуються конкретно такого-то об’єкта задавать в конструкторі. А всі мєтоди шо визиватимуться у цього об’єкта будуть іспользовать ці пєрмєнні.

От так і предлагаю зробить:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $database</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __construct</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">database </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">                'user'</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'root'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">                'password'</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'abc123'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">                'host'</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'localhost'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">                'database'</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'dbank'</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            );</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // шось тут коїться!</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

а в файлі index.php тепер у нас буде тільки от така штука:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require_once</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'application.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    $app </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    $app</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

І якшо ти зараз запустиш свій блог - ти побачиш ровним щотом нічого. Бо в методі run() нічого не виводиться. Давай научимось розбирать адрєс странічки, яку хоче пользоватєль

Закопуєм блог

Тепер давай розберемся от з чим: у нас пользоватєль не хоче бачити таку бяку в адрєсной строкє браузера, як тіпа moo.php?foo=bar&#x26;amp;baz=dao . Йому удобніше, пріятніше читать шось тіпа /moo/bar?baz=dao . Тіпа вони будуть запоминать або тіпа вони зможуть записать на бумажці десь це. Не важно особо, нашо це пользоватєлю - главне зробить його щасливим.

Щас ми будем обільно рефлєксірувать. Єсть в PHP така одна чудєсна пєрємєнна, як $_SERVER . Це масів. В ньому лежить багато інтересних всяких настройок, але нам поки треба буде тільки одна - $_SERVER['REQUEST_URI'] . Як не странно, воно слабо зв’язано з сервером. Це - адрєс, який ввів пользоватєль, тільки без домєна. Так шо, якшо у нас сайт називається &#x3C;a href="http://google.com/search/">http://google.com/search/&#x3C;/a> , а пользоватєль введе в адрєсну строку браузєра &#x3C;a href="http://google.com/search/moo/foo/bar">http://google.com/search/moo/foo/bar&#x3C;/a> , то в соотвєтствующому php-файлі, пєрємєнна оця $_SERVER['REQUEST_URI'] буде мати значення /moo/foo/bar .

Але по умолчанію наш сервер перенаправляє пользоватєля на файл index.php , при цьому рісує цей index.php в адрєс странічки. Нада убрать його відти. Для цього ми візьмем настройки сєрвєра Apache (якшо у тебе ВНЕЗАПНО другий сервер - будем шось думать - пиши мені в лічку) і трошки їх поміняєм.

Першим ділом тобі треба включить расширєніє сервера під назвою rewrite . В лінуксах всяких це робиться в два етапа:

  1. ставиться пакєт `apache2-utils`
  2. включається це расширєніє командой `[sudo] a2enmod rewrite`

Потом тобі треба в корні сайта, рядом з index.php положить файлік .htaccess (начинається ім’я його з крапки!) з таким вмістом:

<code>RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
</code>

Ця штука заставить всі адрєса, шо пользоватєль вводить для цього сайта перенаправлять в index.php . І у тебе в пєрємєнной $_SERVER['REQUEST_URI'] всігда буде адрєс без /index.php .

Тепер давай розіб’єм все, шо нам буде присилать пользоватєль в строчці адрєса условно на три тіпа - контроллєр , екшн цього контроллєра і все остальне (в народі - парамєтри ). Розбивать будем просто - по символу / . Все остальне - це по суті масив $_GET .

ЯКШО НЕ СТРЕЛЬНУЛО то треба в настройках хоста (в лінуксах - /var/www/apache2/sites-available/000-default.conf ) дописати

<code>&#x3C;Directory /var/www/>
        AllowOverride all
        Options FollowSymlinks
        Order allow,deny
        Allow from all
&#x3C;/Directory>
</code>

Шо по суті для папки /var/www (де лежить сайт і, в часності, index.php ) дає можливість через .htaccess мінять настройки сервера.

Давай тепер в методі Application::run() впишем код шоб воно виводило нам наш адрєс:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    echo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $_SERVER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'REQUEST_URI'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Тепер розіб’єм цей адрєс на ім’я контроллєра і екшна. Розбиваєм по символу / і тупо берем перші два елємєнта получєного массіва. Якшо не хватає другого елємєнта - по умолчанію поставим index . Якшо не хватає ще й першого - по умолчанію поставим application .

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$pieces </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array_filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">explode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $_SERVER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'REQUEST_URI'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]));</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controllerName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'application'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$actionName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'index'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

Така хороша функція array_filter() убирає із массіва пусті елементи. А тройним оператором (condition) ? if_true : if_false ми робим круте присвоєніє нужного значєнія в пєрємєнні. І як не странно, але в цьому випадку ключі у масива - 1 і 2 .

Тепер якшо ти виведеш ці пєрємєнні в методі Application::run() і зайдеш на сайт напрімєр по ссилці http://localhost/moo/foo , то ти побачиш як ця штука працює. Якшо передасиш один параметр через слешку: http://localhost/moo - побачиш шо $controllerName = 'moo' а $actionName = 'index' . Якшо два параметра - http://localhost/moo/foo - побачиш шо буде ще й $actionName = 'foo' . А якшо більше - то ніякої різниці вже не побачиш.

Цей момент важно запомнить: якшо наш сайт не знатиме якого контроллєра взять - буде намагатись найти контроллєр всього сайта. Якшо він не буде знати який йому екшн визвати - буде пробувать визвати екшн index .

Почучуть оживляєм

Тепер давай зробим якийсь конкрєтний контроллєр! Положим ми його в папочку controllers . Хай він поки особо нічого крутого не вміє - просто виводить &#x3C;h1>I am alive!&#x3C;/h1> . І це у нас буде екшн index :

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PostingsController</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            echo</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '&#x3C;h1>I am alive!&#x3C;/h1>'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

Тепер у нас стоїть задача аутоматично найти цей класс і визвати нужний метод у нього, якшо пользоватєль попробує зайти по ссилці http://localhost/postings/ або http://localhost/postings/index .

Ми скористаємось такою шикарною штукою PHP як авто-пошук нужних класів. В народі - autoloading . Якшо пишем ми на стареньком PHP 5.0, то у нас ще довго буде возможность пользуватись глобальною магічною функцією __autoload($className) .

Коли ми описуєм цю функцію, PHP буде іспользувать її шоб найти класс, який ми не опреділили, но питаємось іспользувать. В неї приходить один аргумєнт - ім’я класа, який нам нада найти. І ця функція должна шось хотя б попробувать зробити, шоб описати клас з таким іменем або подключити нужний файл, де цей клас описаний.

Ну от напрімєр, ми точно знаєм, шо наші кантроллєри лежать в папці controllers . Так давай научим наш Application находить нужний контроллєр і создавать його об’єкт в методі run() !

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __autoload</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">className</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"controllers/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$className</span><span style="color:#40A02B;--shiki-dark:#A6D189">.php"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $pieces </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array_filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">explode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $_SERVER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'REQUEST_URI'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controllerName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'application'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $actionName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'index'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controllerName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ucfirst</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controllerName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Controller'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controller </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $controllerName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controller</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$actionName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

Трошки заумний код. Начнем з нового: функція ucfirst($text) бере першу букву з $text і перероблює її у верхній регістр. Тоість, якшо було moo стане Moo , якшо було Moo - нічо не поміняється. Функція __autoload просто бере файл з папки controllers/ з імєнєм контроллєра і подключає його.

Тут важний момет нащот самой функції require() : коли ти її визиваєш вона по суті бере код із того файла і вставляє в місце, де ти визвав цю функцію. Точніше, не сам код файла, а виполняє цей файл і всьо шо вийшло в результаті - вставляє в це місце, де ти визвав require . Якщо там опрєдєлєні пєрємєнні чи класи - вони стають опрєдєлєні там де ти визвав require . Але якшо ти його визвав внутрі __autoload - то ці пєрємєнні чи класи стають доступні в усьому файлі, де сработав __autoload . Бо ще __autoload можна на каждий файл свій написать.

Виводим HTML

Якшо ти ще помниш, там де ми визиваєм require - виполняється код файла, який ми подключаєм і все що виполнилось вставляється в те місце.

Давай зробим таку інтересну штуку: зробим файлік який-небудь views/index.html з яким-небудь HTML і в екшні PostingsController::index() просто підключим його:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PostingsController</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'index.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

І якшо зараз зайти на http://localhost/postings - можна буде побачити содєржиме цього файла! І це прекрасно, ящітаю!

У каждого екшна є свій view - оддєльний файлік, який виводить HTML тільки основної частини страніци. Щитай це вміст тега &#x3C;body> . А контроллєр збирає виведений цей HTML і виводить в свій оддєльний view, в якому і описане все вокруг тега &#x3C;body> - щитай це весь HTML, кромє &#x3C;body> . Для контроллєра цей view називається по-особєнному, layout . І от цей лейаут, він може бути один на всі-всі контроллєри, а може бути разний для нєкоторих або і вообщє - свій для каждого кантроллєра.

Так от, давай зробим слєдующім образом: у нас буде папочка views/layouts , де будуть лежать разні шаблончики. І ми зробим один шаблончик, який буде аутоматично подтягуватись для каждого контроллєра і назвем його application.phtml , як контроллєр “по умолчанію”. Замєть, файл має расширєніє .phtml . Це нормально. Це показує шо у нас в файлі є і PHP-код і HTML размєтка. В папочку views/layouts давай положим файлік postings.phtml куди наб’єм допустім такий HTML:

<code>&#x3C;!DOCTYPE html>
&#x3C;html lang="en">
&#x3C;head>
    &#x3C;meta charset="UTF-8">
    &#x3C;title>Document&#x3C;/title>
&#x3C;/head>
&#x3C;body>
    &#x3C;?php echo $body ?>
&#x3C;/body>
&#x3C;/html>
</code>

Тут ми берем якусь пєрємєнну $body і виводим її. Простенький файлік, нічого сложного. Але нам нада звідкись достать цей самий $body . Для цього ми іспользуєм ще одну інтересну плюшку PHP, output buffer . Воно позволяє виполнить якийсь код якби в фоні, а все шо цей код вивів - сохранить в пєрємєнну. Виглядить це так:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ob_start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        echo</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'I am alive!'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ob_end_clean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Якшо ти запустиш цей код - нічого не виведеться. Но зато оцей тєкст, I am alive! можна достать функцієй ob_get_contents() :

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ob_start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        echo</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'I am alive!'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    $content </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ob_get_contents</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ob_end_clean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    echo</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "&#x3C;h1></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$content</span><span style="color:#40A02B;--shiki-dark:#A6D189">&#x3C;/h1>"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span></code>

А от цей код вже виведе &#x3C;h1>I am alive!&#x3C;/h1> . Замєть: ob_end_clean() очищає цей буфєр, куди ложиться вивод всього-всього між ob_start() і ob_end_clean() . І забрати звідки вивод треба до того, як визвать ob_end_clean() .

А якшо ми тепер поміняємо просте echo між ob_start і ob_end на, скажімо, require() ?

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ob_start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'views/index.html'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    $content </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ob_get_contents</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">    ob_end_clean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'views/layouts/postings.phtml'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Виходить, що в $content у нас лежить вміст файла views/index.html , а якшо ми подключаєм лейаут - він виведе HTML з цього лейаута і всередині нього - пєрємєнну $content .

А тепер, якшо ти оцей код написав внутрі PostingsController::index() , ми його переробим. Шоб не писать в каждом екшні каждого кантроллєра багато всяких ob_start , require і прочіх. Опять вертаємось до класа Application , в якому ми описуєм запуск нашого сайта. В нашому чудєсном методі run() ми вже написали шо робить коли пользоватєль заходить на сайт. Давай тепер трошки перепишем цей код шоб обернуть його вивод в нужний нам HTML:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> run</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $pieces </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array_filter</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">explode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'/'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $_SERVER</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'REQUEST_URI'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controllerName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">1</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'application'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $actionName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">])</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $pieces</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#FE640B;--shiki-dark:#EF9F76">2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'index'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controllerClass </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ucfirst</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controllerName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'Controller'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // вичісляєм ім’я view</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $viewFile </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "views/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controllerName</span><span style="color:#40A02B;--shiki-dark:#A6D189">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$actionName</span><span style="color:#40A02B;--shiki-dark:#A6D189">.phtml"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // вичісляєм ім’я layout</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $layoutFile </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "views/layouts/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controllerName</span><span style="color:#40A02B;--shiki-dark:#A6D189">.phtml"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controller </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $controllerClass</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            ob_start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // тут внутрі контроллєра задаються якісь пєрємєнні</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $controller</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$actionName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // рісуєм відповідний view, в якому виводяться пєрємєнні, задані в екшні</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$viewFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // получаєм вивод екшна - наш body</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ob_get_contents</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            ob_end_clean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // виводим лейаут, в якій виводиться body</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$layoutFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

При такому розкладі у нас цей мєтод робить сильно забагато всього. А всі пєрємєнні, які ми задаєм внутрі екшна недоступні всередині view - вони задаються внутрі контроллєра, а рісує в’юху у нас - application. Значить, вертаємось до ООП. Будем трошки усложнять зараз роботу шоб потом писать було проще.

Зробим основний клас для всіх контроллєрів, який буде рісувать свій лейаут і нужні в’юхи. А із application будем визивать якийсь один метод, який просто виведе все шо треба. Цей клас ми, по старой доброй традиції, положим в папку core/ :

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseController</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __invoke</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">controllerName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> $</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">actionName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // вичісляєм ім’я view</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $viewFile </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "views/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controllerName</span><span style="color:#40A02B;--shiki-dark:#A6D189">/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$actionName</span><span style="color:#40A02B;--shiki-dark:#A6D189">.phtml"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // вичісляєм ім’я layout</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $layoutFile </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "views/layouts/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controllerName</span><span style="color:#40A02B;--shiki-dark:#A6D189">.phtml"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            ob_start</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$actionName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // рісуєм відповідний view, в якому виводяться пєрємєнні, задані в екшні</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$viewFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $body </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> ob_get_contents</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            ob_end_clean</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">            // виводим лейаут, в якій виводиться body</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$layoutFile</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

Ми просто щитай перенесли код з одного класа в другий. Замєть, ім’я мєтода називається з двох підкреслень. Ми тоже можем создавать магічні методи, муа-ха-ха! Тепер трошки переробим наш контроллєр PostingsController :

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require_once</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'core/BaseController.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require_once</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'models/Posting.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PostingsController</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseController</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">postings </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

Але тепер дивись: у нас в каждій моделі подключається файл BaseModel.php . Тепер ще нам прийдеться в каждом контроллєрі подключать BaseController.php . Не комільфо. Щас будем рефакторить - всі ці строчки з моделей і з контроллерів можна перенести в Application.php - цей файл у нас по-любому подключається і всігда запускається самий перший.

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require_once</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'core/BaseModel.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require_once</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'core/BaseController.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Application</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // ...</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

Тепер нам треба перемістить views/index.html в views/postings/index.phtml шоб наш Application::run() знайшов його. І з PostingsController::index() убрать весь код - у нас тепер усьо аутоматично!

Ітог

Шо нам дає така сложна сістєма? По-перше, і це дуже важно, нам тепер не треба в усі файли пихать один і той же HTML. По-друге, у нас сайт може мати кучу совєршенно разних по дизайну і вигляду странічок тепер. І шоб їх помінять чи шоб в них встроїть, допустім, виведення всіх постінгів чи якоїсь формочки, нам треба просто вивести туди в’юху. І перероблювать, в случаї чого, треба дуже і дуже мало кода.

Наконєц, чисто для наглядності давай зробим простеньке упражнєніє: виведем в екшні PostingsController::index() всі постінги, іспользуя всі ці лейаути-в’юхи і моделі.

У нас уже є лейаут для контроллєра PostingsController . У нас уже є сам контроллєр. У нас є модель поста. У нас даже є в’юха (і байдуже шо дурна) для цього!

Значить, пробуєм? В екшні ми задамо перемєнну з усіма постінгами. Кстаті, конструктор контроллєра нам уже не треба - вже не актуально, не мейнстрім. А у в’юхє ми просто виведем всі постінги.

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    require_once</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'models/Posting.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PostingsController</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> index</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">postings </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span></code>

І в’юха:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">postings </span><span style="color:#179299;--shiki-dark:#81C8BE">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE">:</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h1</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">echo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">?>&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h1</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"description"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">echo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">description </span><span style="color:#179299;--shiki-dark:#81C8BE">?></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">endforeach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?></span></span></code>

Домашнє заданіє

Воно буде велике. Prepare yourself!

  1. Треба прєдусмотрєть ситуацію, коли ми не найшли нужний класс контроллєра (щитай, не найшли файл) - в таком случаї нада показать ошибку 404 .
  2. Переведи весь блог на контроллєри, в’юхи, лейаути і моделі. Попробуй, чи прощє тепер чи сложніше стало робить це.
Чоткій блог. Часть друга urn:uuid:885d9d7a-1d07-5202-a6f9-a546eeb661ab 2014-07-27T00:00:00Z 2014-07-27T00:00:00Z

Моделі

Єсть така штука як MVC, Model-View-Controller . Це такий прінцип, по якому програма розділяється на три тіпа дєталєй:

  1. Model - отвічає за роботу чісто з базой даних
  2. View - отвічає чісто за отображеніє даних перед пользоватєльом (формочка, HTML, і так далєє)
  3. Controller - отвічає за обработку дєйствій пользоватєля, іспользує моделі і передає їх в’юхам

Так от, модель - це такій клас, який работає з рядочками одної таблички і другими табличками, шо прив’язані до нашої. Але тільки якшо та таблічка, з якою работає модель - главна в цій связі. Тоість, якшо у нас є модель Пост і модель Камєнтік , то модель Пост може вліять на Камєнтікі , а от модель Камєнтік вже нічо не може зробити з Постом . Тут таблічка Пост - главна, а таблічка Камєнтік - просто прив’язана до неї.

В общєм, модель - це такий удобний клас, в якому заникані всі запроси до бази даних. Ти визиваєш метод моделі, а получаєш - масив (або не масив, а тільки один його елємєнт) з запісями з бази даних. Або визиваєш другий мєтод і удаляєш/обновляєш/создаєш рядочки в базі.

Artem Shubovych

Моделі

Єсть така штука як MVC, Model-View-Controller . Це такий прінцип, по якому програма розділяється на три тіпа дєталєй:

  1. Model - отвічає за роботу чісто з базой даних
  2. View - отвічає чісто за отображеніє даних перед пользоватєльом (формочка, HTML, і так далєє)
  3. Controller - отвічає за обработку дєйствій пользоватєля, іспользує моделі і передає їх в’юхам

Так от, модель - це такій клас, який работає з рядочками одної таблички і другими табличками, шо прив’язані до нашої. Але тільки якшо та таблічка, з якою работає модель - главна в цій связі. Тоість, якшо у нас є модель Пост і модель Камєнтік , то модель Пост може вліять на Камєнтікі , а от модель Камєнтік вже нічо не може зробити з Постом . Тут таблічка Пост - главна, а таблічка Камєнтік - просто прив’язана до неї.

В общєм, модель - це такий удобний клас, в якому заникані всі запроси до бази даних. Ти визиваєш метод моделі, а получаєш - масив (або не масив, а тільки один його елємєнт) з запісями з бази даних. Або визиваєш другий мєтод і удаляєш/обновляєш/создаєш рядочки в базі.

Шоб зробити цей клас унівєрсальним до невозможності, представим, шо класс отвічає за роботу з всьою табличкою (вибор рядочків з таблички), а об’єкт цього класа отвічає за роботу з конкретним рядочком з цеї таблички. Робота з цим класом буде виглядіть якось так:

<code><span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// всі пости</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$postings </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// один конкретний пост</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">find</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// не до кінця обновлений пост (в базі ще не сохраньон)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "moo"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// сохранить пост в базі</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">save</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">// удалить пост</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">destroy</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

Сама проста реалізація моделі буде схожа на оце:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $description</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __construct</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> $</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">description</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">description </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $description</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __construct</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> $</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> $</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">description</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">description </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $description</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $results </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">SELECT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id, title, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">description</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FROM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> postings;</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_fetch_assoc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $results</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'title'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'description'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $results</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> find</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $row </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_fetch_assoc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">SELECT</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id, title, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">description</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FROM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> postings </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">WHERE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $id</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">          return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'title'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">],</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'description'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">UPDATE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> postings </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">SET</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> title </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;title'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">description</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;description'</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> WHERE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;id'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">INSERT INTO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> postings (id, title, </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">description</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">) </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">VALUES</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> (</span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;id'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;title'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">, </span><span style="color:#40A02B;--shiki-dark:#A6D189">'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;description'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">)</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DELETE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FROM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> postings </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">WHERE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;id'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Але з таким ращотом, у нас для кожної таблички буде оддєльний клас і оддєльний набор запросов. І вспоминаєм, шо ми рішили не дублірувать код. Будем іспользувать мощ магічних методів PHP!

Нехай ми не знаєм, які поля єсть в табличці. Но всі запроси ці, SELECT/DELETE - вони в основном одінакові і відрізняються тільки для INSERT/UPDATE . Того нам нада так переписать ці INSERT/UPDATE і цей клас, шоб вони работали з любими табличками.

Воспользуємся масивами PHP і магічними методами __set/__get . Ці методи дають можливість описать свою логіку коли програміст записує чи читає неізвєсне поле класа. Напрімєр, якшо у нашого класа Post нема поля moo , то при попитці зробить echo $posting->moo буде визиватись мєтод __get('moo') , а при попитці записать шось туди $posting->moo = 'MOO!' буде визваний __set('moo', 'MOO!') . Приступаєм:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $__data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $__tableName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> getTableName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $class_name </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get_called_class</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> strtolower</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$class_name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 's'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __construct</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$data </span><span style="color:#179299;--shiki-dark:#81C8BE">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $key </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$key</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $__tableName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#D20F39;--shiki-dark:#E78284"> $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTableName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __get</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">field</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$field</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#D20F39;--shiki-dark:#E78284"> $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$field</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __set</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">field</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#E64553;--shiki-dark:#EA999C"> $</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__data</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$field</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $tableName </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> self</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getTableName</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $class </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get_called_class</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $results </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $rows </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">SELECT</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FROM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $tableName;</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$row </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_fetch_assoc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$rows</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $results</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $class</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $results</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> static</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> find</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $row </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_fetch_assoc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">SELECT</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FROM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $tableName </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">WHERE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $id</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">          return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BaseModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            return</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ""</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $fields </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__data </span><span style="color:#179299;--shiki-dark:#81C8BE">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $field </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$field </span><span style="color:#179299;--shiki-dark:#81C8BE">==</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">                    continue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">                }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                $fields</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "`</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$field</span><span style="color:#40A02B;--shiki-dark:#A6D189">` = '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$value</span><span style="color:#40A02B;--shiki-dark:#A6D189">'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">UPDATE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26;gt;__tableName </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">SET</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> implode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">', '</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $fields</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> " WHERE id = '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;id'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $values </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">            foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">__data </span><span style="color:#179299;--shiki-dark:#81C8BE">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $field </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">                $values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$field</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "'</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$value</span><span style="color:#40A02B;--shiki-dark:#A6D189">'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">            $query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">INSERT INTO</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26;gt;__tableName (</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> implode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">', '</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array_keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ") VALUES ("</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> implode</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">', '</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array_values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#179299;--shiki-dark:#81C8BE"> .</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ")"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> delete</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#D20F39;--shiki-dark:#E78284">$this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">            mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">DELETE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FROM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">&#x26;gt;__tableName </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">WHERE</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> '</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$this</span><span style="color:#40A02B;--shiki-dark:#A6D189">-&#x26;gt;id'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Так шо ж за ад тут коїться?

По-перше, цей клас - базовий. Всі слєдующі модельки ми будем наслєдувать від нього. Тоість, весь цей ад у нас коїться тільки один раз - дальше всі моделі виглядять приблизно так:

<code class="language-class">    public function getViewUrl() {
        return "view.php?$this-&#x26;gt;id";
    }
};
</code>

А іспользовать такі моделі тепер - сплошне удовольствіє!

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php $postings </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#179299;--shiki-dark:#81C8BE">::</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">all</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">foreach</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$postings </span><span style="color:#179299;--shiki-dark:#81C8BE">as</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#179299;--shiki-dark:#81C8BE"> ></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h2</span><span style="color:#179299;--shiki-dark:#81C8BE">>&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">echo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">title </span><span style="color:#179299;--shiki-dark:#81C8BE">?>&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">h</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"description"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">echo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">description </span><span style="color:#179299;--shiki-dark:#81C8BE">?></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"read-more"</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">        &#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">echo</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">getViewUrl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">    &#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">div</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;?</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">php </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">endforeach</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?></span></span></code>

По-друге, в конструктор ми передаєм (всігда) поля з таблички, а конструктор - записує їх в масив __data . Ну і в конструкторі ж ми дуже хітро достаєм імя таблички з імєні класа: якшо у нас, напрімєр, клас моделі Posting , то ім’я таблички буде postings .

Ще один ньюанс з приводу імені таблички і того шо ми вертаєм в мєтоді all() : тут іспользується така хітра функція get_called_class() , яка вертає ім’я класа, який визвав поточний мєтод. Воно працює і з наслєдованієм в ООП, тоість якшо запустити отакє:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> whoami</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">        echo</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get_called_class</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Foo</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> extends</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$a </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$a</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">whoami</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$b </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Foo</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$b</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">whoami</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

то воно виведе:

<code>Moo
Foo
</code>

І якшо ми захочем зробить об’єкт дочєрнього класа внутрі батьківського, то ми можем спокойно визвать

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$class </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> get_called_class</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $class</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#179299;--shiki-dark:#81C8BE">...</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span></code>

Ну і всі запроси до бази даних строяться вже іспользуя поля $__data і $__tableName .

А тепер трошки поправим файлову структуру: у нас тепер є кілька файлів, які не відносяться конкретно до цього блога, а, так сказать, єсть каркасом, на якому можна наліпити ше шось. Це BaseModel.php і connect.php . Точніше, connect.php - в ньому задаються параметри подключєнія до бази даних конкретно цього блога. Шо я предлагаю - зробити три папки:

  • core , в якому буде BaseModel.php
  • models , куди положити Posting.php і всі прочі моделі, які наслєдують BaseModel
  • config , куди положить connect.php

Не забудь поправити всі путі у require() !

Замєть, тепер файл connect.php нам треба тільки в одному місці - в BaseModel.php . Шо тоже кагбе упрощає код.

Тоість, тепер у нас має бути якась така файлова структура:

чотка файлова структура

Домашнє завдання

Зроби моделі поста і камєнтіка і застав їх работать внутрі index.php і view.php . Замєть, шо в бєзопасності BaseModel єсть дірка. А ще - і це дуже важно - подивись шо таке PDO і зроби замість всіх mysql_query і прочіх роботу з PDO .

Чоткій блог на PHP. Часть перша urn:uuid:137f93b6-380e-5f14-aeee-7ae71d39456b 2014-07-22T00:00:00Z 2014-07-22T00:00:00Z

Прєдісловіє

Дарагой друг! В цих статтях я розкажу тобі як зробить чоткій блог на чотком язику PHP. Розказувать буду просто, шоб всьо було понятно. Ну шо, паєхалі?

Сістємні трєбованія

Нехай у нас є який-небудь самий стандартний, простий, перший блог на PHP. Така собі кучка файлів для созданія постов, списка постов, перегляду оддєльного поста, реєстрації, логіна і логаута, камєнтіруванія… Просто купа файлів. В цих файлах у нас і HTML, і PHP код.

Artem Shubovych

Прєдісловіє

Дарагой друг! В цих статтях я розкажу тобі як зробить чоткій блог на чотком язику PHP. Розказувать буду просто, шоб всьо було понятно. Ну шо, паєхалі?

Сістємні трєбованія

Нехай у нас є який-небудь самий стандартний, простий, перший блог на PHP. Така собі кучка файлів для созданія постов, списка постов, перегляду оддєльного поста, реєстрації, логіна і логаута, камєнтіруванія… Просто купа файлів. В цих файлах у нас і HTML, і PHP код.

Приблизно це виглядить отак:

нечотка файлова структура.

І дуже-дуже нада знать CSS, HTML, ООП в PHP і потом, може, JavaScript і jQuery.

Перед началом роботи краще привести в порядок HTML і CSS - розбити всьо красіво по папочкам (CSS - оддєльно, рісунки - оддєльно, PHP-файли - оддєльно); убрать з HTML всі атрібути style="..." , всюди пороздававши класи елементам; пообертать атрібути в кавички ( height="15px" , а не height=15px ) і так далєє. Шоб ще прощє було потом читать код.

Чистим HTML код

Першим ділом ми будем умєньшать кількість кода, шо є в нашом блогє. В народі це називається принцип DRY, Don’t Repeat Yourself . Розшифровується воно як пацани не повторяють . В RubyOnRails і других крутих штуках шось подобне реалізовано так, шоб весь HTML-код і PHP-код (ну або там Ruby-код, Python-код, будь-який-язик-программіруванія-код) були оддєльно, ну або хотя би по мінімуму PHP і по максімуму HTML.

Тоість, єсть такі штуки, які називаються View і єсть такі штуки які називаються Controller . Так от, в View - у нас чисто виводиться інформація, форматірується з помощю HTML, а чучуть кода все ще є для всяких циклов, іфов або визовов методов Helper ‘ов (якшо нада хітро вивести шось - ссилку, напрімєр, на пост або на удалєніє поста - шоб самому не писати весь адрєс ссилки - можна воспользоватись допоміжним мєтодом; од того і Helper). А в Controller - весь PHP код, який получає дані з бази даних, методи-Helpers, і вобщє нема HTML кода.

Виглядить це якось отако: якшо у нас було

нечоткий код index.php

то має стати

чоткий код index.php

Так шо першим ділом ми будем убирать з нашого HTML весь лишній PHP код. Да, і желатєльно заранєє договоритись шо до цього момєнта HTML має бути подчищений от лишнього CSS - як мінімум всі style="css-code" замінить на class="class-name" . Шоб простіше було орієнтіруватись в коді.

Перший кантроллєр

Давай попробуєм зробить сначала контроллєр для странічки index.php , в якій отображаються всі пости. По старой, доброй традіції, ми зробим оддєльний файл з классом і подключим його зверху index.php через require_once() .

Якшо ти помниш ООП, то у классов є такій магічний мєтод як конструктор. Так вот, в ньому ми будем робити круту таку штуку як загрузку даних (із бази, із сесії, із куков) в пєрємєнні, які потом будем іспользовать.

Напрімєр, якшо ми перероблюємо список постінгов, то нам нада масив всіх наших постів з бази взять. Якшо нам там же треба пользоватєль, який залогінений - нам із сесії треба його взять. Або рішить, шо його нема.

Виглядить це буде отако:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">require</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'connect.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PostingsController</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    var</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $postings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $user</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> __construct</span><span style="color:#7C7F93;--shiki-dark:#949CBB">()</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // получаєм з бази пости</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">        $res </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">SELECT</span><span style="color:#179299;--shiki-dark:#81C8BE"> *</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> FROM</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> postings</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">        $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">postings </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> array</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        while</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$row </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> mysql_fetch_assoc</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$res</span><span style="color:#7C7F93;--shiki-dark:#949CBB">))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">postings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $row</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">        // берем із сесії пользоватєля</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">        if</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> (</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">isset</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$_SESSION</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'user'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]))</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $_SESSION</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'user'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> else</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#D20F39;--shiki-dark:#E78284">            $this</span><span style="color:#179299;--shiki-dark:#81C8BE">-</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">&#x26;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">gt</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">user </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> null</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">        }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">    }</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">};</span></span></code>

Давай зразу робить чотку структуру файлов. Зробим папку controllers і туди будем сохранять контроллєри в файлах ***_controller.php . Тоість, наш оцей клас ми положим в файл controllers/PostingsController.php .

Тепер в файлі index.php в самом верху, де у нас раньше подключалась база даних і прочі штуки, у нас буде тільки require() цього контроллєра. Но поки у нас архітєктура не дуже крута, то ще одну строчку прийдеться добавить:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">require_once</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">'controllers/PostingsController.php'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controller </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> new</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> PostingsController</span><span style="color:#7C7F93;--shiki-dark:#949CBB">();</span></span></code>

І тепер всі оці while ($posting = mysql_fetch_assoc($res)) { ... } можна замінить на foreach ($controller-&#x26;gt;postings as $posting) { ... } , а $_SESSION['user'] - на $controller-&#x26;gt;user . І це кручє, бо ми можем юзера і в базі тримать, і ще невідомо де. Ну а постінги - так вроді прощє іспользувать.

Перший хелпєр

А тепер давай ще додамо перший метод, який упростить жизнь і покаже мощь архітєктури. Він нам помогатиме формірувать URL до постінга. Це шось тіпа:

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a href</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"view.php?id=&#x3C;?php echo </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting</span><span style="color:#40A02B;--shiki-dark:#A6D189">['id'] ?>"</span><span style="color:#179299;--shiki-dark:#81C8BE">>...&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

буде замінений на

<code><span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">&#x3C;</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a href</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189">"&#x3C;?php echo </span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$controller</span><span style="color:#179299;--shiki-dark:#81C8BE">-></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">viewPostingUrl</span><span style="color:#40A02B;--shiki-dark:#A6D189">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$posting</span><span style="color:#40A02B;--shiki-dark:#A6D189">) ?>"</span><span style="color:#179299;--shiki-dark:#81C8BE">>...&#x3C;/</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">a</span><span style="color:#179299;--shiki-dark:#81C8BE">></span></span></code>

Согласись, якшо внезапно поміняється путь до файла, який буде отвічать за просмотр поста, то в першому случаї прийдеться багато де мінять цю строчку, а в другому случаї - тільки в кантроллєрі.

Отак, у нас цей метод буде принімать масів і вертать строчку… Зробим його пока шо простим:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> function</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> viewPostingUrl</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;--shiki-dark:#EA999C">$</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    $id </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> $posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">];</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    return</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "view.php?id=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">$id</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span></code>

Домашнєє заданіє

Попробуй зробити всякі другі хелпери - для ссилок на удалєніє постов, на редактіруваніє, і прочі.

From ActiveModel to ActiveRecord urn:uuid:1b438cca-476a-5582-b27b-13220c6259ae 2014-04-17T00:00:00Z 2014-04-17T00:00:00Z From ActiveModel to ActiveRecord Artem Shubovych

This short article covers some steps you need to implement to get your own ActiveRecord implementation.

Sample ActiveModel looks like this:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  include</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActiveModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">Validations</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  attr_accessor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">tags</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  validates </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">presence</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  validates </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">presence</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">attributes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {})</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    set_default_values</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self.create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">attributes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">save</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  protected</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> set_default_values</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

First trouble is that ActiveModel does not provide any attribute access API. Or I did not google enough. So we need to create our own!

Let us have an instance variable @attributes where we will store our model’ data. We need to define getter and setter methods for all the attributes of our model. This may be done with the attr_accessor method. But when user sets the value for some attribute, we should store that in our @attributes variable. And here is the first step to our black magic: we will override the attr_accessor method .

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActiveAttributes</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> attr_accessor</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">*</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    args</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      define_method</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_sym</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_sym</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      define_method</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">="</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_sym</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">value</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_sym</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> value </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

I just wrapped the code into a single module. Remember: when you include the module in a class, all the module’ methods become class methods.

Now we will include this module before attr_accessor calls . But beware: you need to declare an @attributes instance variable in the constructor!

And let’s just agree with the following convention: all our attribute names should be symbols .

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  include</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActiveModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">Validations</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  include</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> ActiveAttributes</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  attr_accessor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">tags</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  validates </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">presence</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  validates </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">presence</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">attributes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {})</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    @attributes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    set_default_values</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self.create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">attributes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">save</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  protected</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> set_default_values</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Now, we can implement our constructor. We now have all the attributes’ getters and setter and thus we can simply call them in our constructor:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  include</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActiveModel</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">Validations</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  include</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> ActiveAttributes</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  attr_accessor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">tags</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  validates </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284">title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">presence</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  validates </span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#D20F39;--shiki-dark:#E78284">body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">presence</span><span style="color:#179299;--shiki-dark:#81C8BE"> =></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> true</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">attributes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {})</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    @attributes </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">symbolize_keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">each</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">      v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">symbolize_keys!</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">is_a?</span><span style="color:#FE640B;--shiki-dark:#EF9F76"> Hash</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">      send</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">="</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> respond_to?</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">="</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_sym</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    set_default_values</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> self.create</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">attributes</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {})</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">).</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">save</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  protected</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> set_default_values</span></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    # ...</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Now let’s implement some basic model persisting. First, we should not forget about our validations and add valid? test to the save method.

Let’s say our save method should return the model instance. Thus, we should put the model’ data into the database and get the id for that data (if we put the data with the INSERT statement).

So there is an important caveat: in order to get the correct model id , you need to get it from database in the same transaction as the update/insert statement . The mysql2 gem does support multiple query statements in a single transaction. But to perform such a query, you will need to set the MULTI_STATEMENTS flag when creating a Mysql2::Connection instance.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  set_default_values</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unless</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> valid?</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @connection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mysql2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Client</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#D20F39;--shiki-dark:#E78284"> flags</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mysql2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Client</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">MULTI_STATEMENTS</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">merge</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(...))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">  # ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  self</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">rescue</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  self</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">ensure</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @connection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">close</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Here I used the instance variable @connection to make it available within the rescue and ensure statements.

Now we will use our instance variable, @attributes to create an SQL query:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  set_default_values</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unless</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> valid?</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @connection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mysql2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Client</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#D20F39;--shiki-dark:#E78284"> flags</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mysql2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Client</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">MULTI_STATEMENTS</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">merge</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(...))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blank?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    columns </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">`"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ','</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    values </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'NULL'</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      else</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActionController</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Base</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">helpers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sanitize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">'"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ','</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "INSERT INTO postings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> volume </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columns </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">) VALUES (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> values </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mapping </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">` = </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NULL'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActionController</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Base</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">helpers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sanitize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ','</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "UPDATE postings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> volume </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> SET </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mapping </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> WHERE id = </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  self</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">rescue</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  self</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">ensure</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @connection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">close</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

I used the ActionController::Base.helpers.sanitize helper method to escape the query parameters.

Now we should simply wrap our query into a transaction and get an id from the database.

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> save</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  set_default_values</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  return</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> self </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">unless</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> valid?</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @connection </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mysql2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Client</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#7C7F93;--shiki-dark:#949CBB">({</span><span style="color:#D20F39;--shiki-dark:#E78284"> flags</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Mysql2</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Client</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#FE640B;--shiki-dark:#EF9F76">MULTI_STATEMENTS</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">merge</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(...))</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">].</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">blank?</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    columns </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">keys</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">`"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ','</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    values </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">values</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> do</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        'NULL'</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      else</span></span>
<span class="line"><span style="color:#40A02B;--shiki-dark:#A6D189">        "'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActionController</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Base</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">helpers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sanitize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">'"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">      end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    end</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ','</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "INSERT INTO postings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> volume </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> columns </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">) VALUES (</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> values </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">)"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  else</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    mapping </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">map</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> |</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">|</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "`</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> k</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_s</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">` = </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">nil?</span><span style="color:#179299;--shiki-dark:#81C8BE"> ?</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'NULL'</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> ActionController</span><span style="color:#7C7F93;--shiki-dark:#949CBB">::</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic">Base</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">helpers</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">sanitize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">v</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">'"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">join</span><span style="color:#40A02B;--shiki-dark:#A6D189"> ','</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "UPDATE postings</span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> volume </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> SET </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> mapping </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189"> WHERE id = </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> }</span><span style="color:#40A02B;--shiki-dark:#A6D189">"</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  query </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "START TRANSACTION; </span><span style="color:#7C7F93;--shiki-dark:#949CBB">#{</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> query </span><span style="color:#7C7F93;--shiki-dark:#949CBB">}</span><span style="color:#40A02B;--shiki-dark:#A6D189">; SELECT LAST_INSERT_ID() AS id; COMMIT;"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @connection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">query</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  while</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @connection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">next_result</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    result </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> @connection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">store_result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">to_a</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> rescue</span><span style="color:#D20F39;--shiki-dark:#E78284"> nil</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[</span><span style="color:#40A02B;--shiki-dark:#A6D189">'id'</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> if</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">present?</span><span style="color:#179299;--shiki-dark:#81C8BE"> and</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">present?</span><span style="color:#179299;--shiki-dark:#81C8BE"> and</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> result</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">first</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">has_key?</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'id'</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  self</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">rescue</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  self</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">ensure</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @connection</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">close</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

Quite big method, sure. Yet, it performs all the UPDATEs and INSERTs for us.

Let’s add some attribute with the default value, created_at and check how the whole class works:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">require</span><span style="color:#40A02B;--shiki-dark:#A6D189"> 'date'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">attr_accessor</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> :</span><span style="color:#D20F39;--shiki-dark:#E78284">created_at</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic"># ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">protected</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> set_default_values</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">  @attributes</span><span style="color:#7C7F93;--shiki-dark:#949CBB">[:</span><span style="color:#D20F39;--shiki-dark:#E78284">created_at</span><span style="color:#7C7F93;--shiki-dark:#949CBB">]</span><span style="color:#179299;--shiki-dark:#81C8BE"> =</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> DateTime</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">now</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

And the test:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">p </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Posting</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#8839EF;--shiki-dark:#CA9EE6">new</span><span style="color:#D20F39;--shiki-dark:#E78284"> title</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello, ActiveModel!"</span><span style="color:#7C7F93;--shiki-dark:#949CBB">,</span><span style="color:#D20F39;--shiki-dark:#E78284"> body</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#40A02B;--shiki-dark:#A6D189"> "Hello, Database!"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">save</span></span>
<span class="line"></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">puts</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> p</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">created_at</span></span></code>
What i always forget about when having an interview urn:uuid:3d90878b-e7ee-5fe1-b511-abce06ff12df 2014-04-12T00:00:00Z 2014-04-12T00:00:00Z What i always forget about when having an interview Artem Shubovych

The Ruby interview

I am always being asked at least two questions. Just to verify that I know Ruby basics.

  • What is the main difference between Module and Class?

That is so simple and obvious! Yet it’s too easy to forget… The answer is: you can not instantiate a Module . See, Modules in Ruby do not have constructors. Yeah, they may contain variables, but they do not have an initialize method.

You could define one this way:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">module</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Moo</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  def</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> initialize</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#E64553;font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic">x</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    @x </span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> x</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">  end</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">end</span></span></code>

But when you try to call Moo.new you will get a method missing error. When you try to run Moo.initialize you will get a private method called error.

So yes, there is no way to instantiate Modules.

  • What’s the difference between Proc, lambda and block?

This is simple enough to remember as the answer contains only a few points:

  1. Proc is an object; block is not
  2. Proc does not check the number of arguments; lambda does
  3. lambda returns from itself; Proc returns from the outer (containing the Proc call) method
  • What is REST (application)?

The answer on that question hardly depends on what the asking person means.

So, I got two possible correct answers :

a. That is the principle of web application development, when the application responds to a request, depending on which HTTP method was provided (PUT, GET, POST, DELETE, OPTIONS) .

b. This is a way of encapsulation Resource and its Handlers. That is a bit hard to explain. Something like “you have to split your application to Resources” .

  • Does Module is the ancestor of Class or does the Class is the child of Module?

This question, actually, may be asked on Class , Module or Object classes. This question is interesting when you do not know the answer.

The reality is plain however:

<code><span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">irb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span><span style="color:#FE640B;--shiki-dark:#EF9F76">005</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Object</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">superclass</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> BasicObject</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">irb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span><span style="color:#FE640B;--shiki-dark:#EF9F76">006</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Class</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">superclass</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> Module</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">irb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span><span style="color:#FE640B;--shiki-dark:#EF9F76">007</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Module</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">superclass</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#FE640B;--shiki-dark:#EF9F76"> Object</span></span>
<span class="line"><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">irb</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">main</span><span style="color:#7C7F93;--shiki-dark:#949CBB">):</span><span style="color:#FE640B;--shiki-dark:#EF9F76">008</span><span style="color:#7C7F93;--shiki-dark:#949CBB">:</span><span style="color:#FE640B;--shiki-dark:#EF9F76">0</span><span style="color:#179299;--shiki-dark:#81C8BE">></span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> BasicObject</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic">superclass</span></span>
<span class="line"><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#D20F39;--shiki-dark:#E78284"> nil</span></span></code>

So, you can even draw a chain:

<code><span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">BasicObject </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Object </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Module </span><span style="color:#179299;--shiki-dark:#81C8BE">=></span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> Class</span></span></code>

Some hints

  • Think oral. Show an interviewing person how your thought flow. That is the good practice. It shows that you can think not just remember . And you could get to some friendly talk when you say some magic keyword or tell something the interviewer is interested in.

  • When I am asked of Rails best practices , or just creating my web application, I should never forget one core principle: web application controllers (looking at Rails’ MVC) should be thin . So, the most logic at Controller ’s action should get or set some data on Model and provide a response. Nothing more.

JPA with SQLite autoincrement troubles urn:uuid:07b96e60-37f3-5198-aeab-3db71a30fe86 2014-04-03T00:00:00Z 2014-04-03T00:00:00Z JPA with SQLite autoincrement troubles Artem Shubovych

Today i’ve got an exception when JPA was trying to insert a new row to a table.

My model definition was like this:

<code><span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">@Entity</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">public</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> class</span><span style="color:#DF8E1D;font-style:italic;--shiki-dark:#E5C890;--shiki-dark-font-style:italic"> Merchant</span><span style="color:#7C7F93;--shiki-dark:#949CBB"> {</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    @Id</span></span>
<span class="line"><span style="color:#FE640B;--shiki-dark:#EF9F76">    @GeneratedValue</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">strategy</span><span style="color:#179299;--shiki-dark:#81C8BE">=</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">GenerationType</span><span style="color:#7C7F93;--shiki-dark:#949CBB">.</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">IDENTITY</span><span style="color:#7C7F93;--shiki-dark:#949CBB">)</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> int</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> id</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    private</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> String</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5"> name</span><span style="color:#7C7F93;--shiki-dark:#949CBB">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    public</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> Merchant</span><span style="color:#7C7F93;--shiki-dark:#949CBB">(){</span><span style="color:#7C7F93;--shiki-dark:#949CBB">   }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#7C7F93;font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic">    // ...</span></span></code>

And the table creation script was the following:

<code><span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">CREATE</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> TABLE</span><span style="color:#1E66F5;font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic"> MERCHANT</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">(</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ID </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">INTEGER</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> PRIMARY KEY</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    NAME</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> TEXT</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    BANKNAME </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">TEXT</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    SWIFT </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">TEXT</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    ACCOUNT </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">TEXT</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    CHARGE </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">REAL</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#8839EF;--shiki-dark:#CA9EE6">    PERIOD</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> INTEGER</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    MINSUM </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">REAL</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span><span style="color:#4C4F69;--shiki-dark:#C6D0F5">,</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">    TOTAL </span><span style="color:#8839EF;--shiki-dark:#CA9EE6">REAL</span><span style="color:#8839EF;--shiki-dark:#CA9EE6"> NOT NULL</span></span>
<span class="line"><span style="color:#4C4F69;--shiki-dark:#C6D0F5">);</span></span></code>

I faced some strange exceptions like id could not be null , SQL error or missing database (near “values”: syntax error) , etc.

The solution to this consists of two steps:

  • in database: remove the AUTOINCREMENT and NOT NULL annotations from the ID column as SQLite will automatically increment its value (in DB)
  • in entity’ code: remove the GenerationStrategyType from the id member annotation
Understanding the beauty of JSF urn:uuid:2b23dd54-513b-593b-b7c0-8d781b701e46 2014-04-03T00:00:00Z 2014-04-03T00:00:00Z Understanding the beauty of JSF Artem Shubovych

My web framework of choice is Ruby On Rails. It's perfect for me. Not because of its scalability or performance, but because of its architecture. You do not need to do lot of work to create a website or a webservice. Ruby Gems have all the power you will ever need. Ruby itself allows you to do even a black magic nicely.

It's true to say that i am a RoR fan.

So when i started learning JSF i thought Gosh! It's ugly! It's totally impossible to work with! . But in a while i realized that small yet mighty concept, i even did not imagine to be thinking of.

See, when you write a website, you need two things to be done:

  • give a user static content ; user just should see something on a display!
  • take user data, process it and perform previous step ; in order to make a dynamic website (which is 90% of all the websites you've seen, i guess) you should use web forms and process them

The last thing i did not mention here (because i did not dive in it yet) is: just use that javascript . You would never provide user-friendly interface on the web until you get full control of what's going on client' side. That's the purpose of JavaScript. Different hints and tips, asynchronous operations, messages and other cool stuff making your UI looking great is the JS part.

But in other cases you use resources . That's the bundle of data, stored (maybe) in database and being controlled by user via the forms.

Any form (yes, just any ) could be described as relying on some resource. Login form? It uses User resource. Search form? It uses the SearchQuery resource. Post creation form? It serves Post !

So, that powerful concept i was talking above is the principle a Managed Java Bean describes the Resource wired to the User Interface .

See, when you show a form to a user - you get your database row maped onto a Java Bean. When user saves the form with the new data - that data gets stored in the same Bean and the method you've set to commandButton or whatever is invoked.

Just think of it! You are doing exactly the same with all those Rails, Play, Django or any other web framework, when you are creating a dynamic website!

incompatible character encodings: UTF-8 and ASCII-8BIT urn:uuid:eea8c811-b3da-55ce-a528-19c757acb9c8 2012-08-16T00:00:00Z 2012-08-16T00:00:00Z incompatible character encodings: UTF-8 and ASCII-8BIT Artem Shubovych

Just got the following error in my Rails project (Rails 3.2.6, Ruby 1.9.3):

<code>ActionView::Template::Error (incompatible character encodings: UTF-8 and ASCII-8BIT)
</code>

That was caused by the case when MySQL record (ActiveReciord object, actually) contained UTF-8 characters and i was trying to output those chars in my template. But mysql gem does not support those. It needs some hacking.

Luckily, there is more convenient way to solve the problem. The solution of this issue now appears too easy:

  • Install the mysql2 gem
  • Use adapter: mysql2 instead of adapter: mysql in your config/database.yml file
My coursework. Two months later urn:uuid:fec71f22-3a6e-586d-9350-2449d1d312f7 2012-04-23T00:00:00Z 2012-04-23T00:00:00Z My coursework. Two months later Artem Shubovych

My coursework: two months later. No, i was not doing all that stuff for two months - i... "freezed" the project for that time 😜 Actually, the greatest portion of job was done in one day - 22.04.2012 .. 23.04.2012 😁

My coursework becomes a bit more interesting urn:uuid:703369e4-553c-581e-84a4-10d1609e148f 2012-02-27T00:00:00Z 2012-02-27T00:00:00Z My coursework becomes a bit more interesting Artem Shubovych

My coursework becomes a bit more interesting 😁